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) <------\ l (108 = 01101100 => 00000011) <-----/| o (111 = 01101111 => 00000100) <-\ | (32 = 00100000 => 00000101) | | w (119 = 01110111 => 00000110) | | o (111 = 01101111 => 00000100) <-/ | r (114 = 01110010 => 00000111) | l (108 = 01101100 => 00000011) <------/ 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 <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"> <=></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"> <</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"><<</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"> <=></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"> &&</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"> <string></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <map></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <queue></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <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"><</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<</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<</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<</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"><</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"><</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"><</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"><</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<</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"><</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"><</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">&&</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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "'"</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:#179299;--shiki-dark:#81C8BE"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "'"</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"> 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"><<</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"> <string></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <map></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <queue></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <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"><</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<</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<</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<</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"><</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"><</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"><</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"><</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<</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"><</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"><</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">&&</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">&&</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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Input: "</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:#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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Encoded: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> <<</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> encoded </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:#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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Decoded: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> <<</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> decoded </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:#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.
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:
current_code = 0
and
current_length = 0
, iterate over each
code length
(assume iterator is
length_i
):
current_length
, left shift
current_code
by the difference
length_i - current_length
current_code
, filling the unused left-most bits with zeroes
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' << 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' << 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"><<=</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"><</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"><</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">&</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">&</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"> <</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"><</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"><</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"><<=</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"><</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>
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) << 1 => code = 00;
create <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) << 1 => code = 100;
create <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) << 1 => code = 1100;
create <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"><<=</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"><<</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:
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)
0
3..10 times, use code
17
and extra bits
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:
0
0, 0
(two zero bytes)
17
followed by
0
for 3 zeros
1
for 4 zeros
2
for 5 zeros
7
for 10 zeros
18
followed by
0
for 11 zeros
1
for 12 zeros
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"><</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"><</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"> &&</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"><<</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"><<</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"> &&</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"><<</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"><<</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"><<</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"><</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"><</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"><</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 256</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:#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"><</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"> &&</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"><</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:
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"><<=</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"><</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"> &&</span><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"> 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"><<</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"><<</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"><<</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"><<</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"><<</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"><<</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"><<</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"><<</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"><</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"> &&</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"> <</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"><<</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"><<</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"><<</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"><<</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"><<</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>
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"><<</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>
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.
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.
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.
The quick action menu has 6 tabs:
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.
In my case it looks like this (ordered by the usage frequency, descending - from most used to least):
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.
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):
And there are a few quality-of-life improvements:
The config I have at the moment allows the following:
<leader>n
toggles NeoTree
.github
, which are hidden by default)
s
performs a Flash search (with literal references to different points in text)
S-s
performs a treesitter Flash search
<leader>t
toggles a terminal
C-\ C-n
switches terminal to Normal mode, but I also remapped it to
<Esc><Esc>
i
switches terminal to Insert mode
C-left
/
C-right
goes through the jumplist (similarly to back/forward in IntelliJ / VSCode)
ys<motion><character>
wraps selected text in a specified character
cs<old char><new char>
changes the wrapped character around text under cursor from
<old char>
to
<new char>
ds<char>
deletes wrapped character around text under cursor
gcc
comments / uncomments the line
gc
comments the selected block of text
<Esc>
in Normal mode sends
nohlsearch
to remove search highlights
<leader>u
shows a list of changes (undo tree), aka local file history
C-n
/
C-<down>
/
C-<up>
creates a new cursor for the same word occurrences / below current cursor / above current cursor
S-k
shows the hint for the symbol under cursor
<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
<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;
<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
<leader><leader>
opens a quick action menu (Telescope builtin)
<leader>f
opens search in files
<leader>gf
opens search only in files tracked by Git
<leader>b
opens a list of NeoVim buffers, ignoring current buffer and sorting by last used timestamp
<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
<leader>q
toggles quickref buffer
<leader>l
toggles locations buffer
Aside from ridiculous amount of time spent configuring Neovim, it ticks most of my boxes:
<leader>b
gd
nvim-cmp
)
C-space
nvim-treesitter
with customized
incremental_selection
): initialize treesitter selection mode with
gsn
and then increment / decrement node selection with
gss
and
gsm
<leader>/
(
telescope
+
telescope-live-grep-args
,
rg
-powered)
gra
/
gcc
/
gc<object>
(e.g.
gcaw
- comment word)
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
<leader>e
(compared to
<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<char>
) and change the surrounding (
mr<from><to>
) and delete the surrounding (
md<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
<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:
<lead>b
buffer list
<lead>e
file explorer; far superior to file list
<lead>/
search
<lead>d
show diagnostics (hints, errors, warnings, etc)
,
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
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)
=
/
<
/
>
- format / unindent / indent selection
:pipe
or
|
- send selection to an external program and replace selection with the output of said program
%{}
, for instance,
%{cursor_line}
or
%{buffer_name}
, so you can pass in the filename to the external tool
%
- select an entire buffer (file)
<lead><c>
/
<lead><C>
- comment/uncomment the selection
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
<lead>j
)
gd
/
gD
- go to definition / declaration
gr
- go to references
"+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:
<leader>b
gd
C-x
m<selection><see tooltip>
<leader>/
(simplified)
<leader>a
(depends on LSP)
/
<leader>c
<leader>f
<leader>S
(capital
S
for workspace symbols, lowercase
s
for current file symbols) (partial)
<leader>r
%
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
gi
(depends on LSP)
|
(pipe it), then specify external program (
ccase -t snake
, for instance)
TBD
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:
gsn
followed by
gss
;
ysaw"
and
cs[(
and
ds"
)
Helix:
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.
<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"> <></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
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<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"><</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"><</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<</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<</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<</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<</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<</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<</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<</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<</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<</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<</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<</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<</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<</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<</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<</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<</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<</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<</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!=<</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<</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<</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<</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<</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<</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">> > > const&, </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<</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<</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<</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">> > > const&)</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:
for (auto i=vec.size()-1; i>0; i--)
is the fastest
--i
is
5%
slower than
i--
i++
is
3%
slower than
--i
7%
slower than
i--
++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.
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 & 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>
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:
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"><</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"> <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"><</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"><</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"><</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"><</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"><</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"><</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<</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"><</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"><</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<</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"><</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<</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">&</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.
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.
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:
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.
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,
<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"> <</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"></</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"> <</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"> <</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"></</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"> <</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"> <</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"> </</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"> </</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"> <</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"> <</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"> </</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"> </</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"> <</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"> <</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"></</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"> <</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"> <</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"> </</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"> </</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"> <</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"> <</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"> <</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"> </</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>
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"> <</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"> <</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"> </</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"> </</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"> <</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"> </</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"> <</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"> <</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"> </</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"> </</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"> <</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"> </</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"> <</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"></</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"> <</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"></</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"> <</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"> <</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"></</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"> </</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"> <</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"> <</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"></</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"> <</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"></</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"> </</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>
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"> <</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"> </</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"> <</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"> </</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"> <</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"></</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"> <</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"> <</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"></</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"> </</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"> <</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"> <</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"></</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"> <</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"></</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"> </</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"> <</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"></</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]&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>
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>
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"> <</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"> </</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>
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"> <</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"> <</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"> <</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"> </</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"> <</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"> <</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"> <</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"> </</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"><</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"><</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"> <</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"> <</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"> <</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"> <</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"> </</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"> <</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"></</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"> <</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"> <</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>
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"> <</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"> <</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">></</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"> </</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"> '<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">></i>&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 <em><b style=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"color: #5ebebe"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">>CSS</b> color</em> <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</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"> <</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"> <</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"> <></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"></></span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"></</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"> </</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"> <</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"> <</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"> <</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"> </</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"> <></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"> </></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"> <</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>
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"> <</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"></</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"> <</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"> <</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"> </</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"> <</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"> <</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"><</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"> <</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"><</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"> </</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"> </</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"> <</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"> <</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"> <</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"> <</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"> <</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"> <</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"> </</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"> </</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"> </</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"> </</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"> </</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
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:
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:
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"> <</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"></</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"> <</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"> <</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"><</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"> <</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"><</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"> </</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"> </</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"> <</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:
On a flip side, the idea itself could actually bring a lot of positives if cooked properly:
dispatch()
call, through the reducers and back to the components connected to the store via component props
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:
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:
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"><-</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"><-</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"><-</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"> <></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"><-</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"><-</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"> <<<</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"><-</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"><-</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"> <></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:
Aff
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"><-</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"><-</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"> <></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"><-</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"><-</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"><-</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"><-</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?
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!
Bun is a combined alternative for NodeJS, package manager (
npm
/
yarn
/
pnpm
), bundler (
vite
/
webpack
/
esbuild
) and test runner (
vite
/
jest
).
| 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)
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.
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>
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>
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.
This one had the most issues on my end.
react-testing-library
Bun declares support for
react-testing-library
, which worked as expected.
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 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>
Fragment
import alongside
<>
If a component contains both
import { Fragment } from 'react'
and uses a shorthand
<>
, 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.
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.
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.).
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.
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"><-</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:
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">"<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">"<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"> <></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show shape) </span><span style="color:#179299;--shiki-dark:#81C8BE"><></span><span style="color:#40A02B;--shiki-dark:#A6D189"> " is "</span><span style="color:#179299;--shiki-dark:#81C8BE"> <></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"><-</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"><-</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
<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"><-</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"><-</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"> <></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show shape) </span><span style="color:#179299;--shiki-dark:#81C8BE"><></span><span style="color:#40A02B;--shiki-dark:#A6D189"> " is "</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:#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"><-</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"><-</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"><-</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>
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">&&</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">&&</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">&&</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">&&</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">&&</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">&&</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">&&</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">&&</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">&&</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">&&</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">&&</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">&&</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"><-</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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">&&</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">(<~>)</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"> <~></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">(<->)</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"> <-</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"> <></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show i) </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"> 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"><-</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"><></span><span style="color:#40A02B;--shiki-dark:#A6D189"> " is "</span><span style="color:#179299;--shiki-dark:#81C8BE"> <></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"><-</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"><-</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"><-</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"><-</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"> <></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> err </span><span style="color:#179299;--shiki-dark:#81C8BE"><></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 <- decodeJson json
-- Check which fields are present
maybeCollection :: Maybe String <- obj .:? "collection"
maybeDocument :: Maybe String <- obj .:? "document"
maybeTable :: Maybe String <- obj .:? "table"
let hasCollection = isJust maybeCollection
let hasDocument = isJust maybeDocument
let hasTable = isJust maybeTable
case hasCollection, hasDocument, hasTable of
true, true, false -> do
collection <- obj .: "collection"
document <- obj .: "document"
pure $ DocumentLocation { collection, document }
true, false, false -> do
collection <- obj .: "collection"
pure $ CollectionLocation { collection }
false, false, true -> do
table <- 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: " <> err
Right location -> do
log $ "Parsed CollectionLocation: " <> show location
let documentJson = """{"collection": "users", "document": "user123"}"""
case parseJobLocation documentJson of
Left err -> log $ "Document parse error: " <> err
Right location -> do
log $ "Parsed DocumentLocation: " <> show location
let tableJson = """{"table": "analytics"}"""
case parseJobLocation tableJson of
Left err -> log $ "Table parse error: " <> err
Right location -> do
log $ "Parsed TableLocation: " <> show location
let invalidJson = """{"data": "something"}"""
case parseJobLocation invalidJson of
Left err -> log $ "Expected error: " <> err
Right location -> log $ "Unexpected success: " <> 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 <- 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
bimapfunction 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 <- 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"><</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"><</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"><</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"><</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"><</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.
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.
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:
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"> <</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"> <</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"> <</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"> <</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
.
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"><</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">&&</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"><</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">&&</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"><</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">&&</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"><</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">&&</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"><</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">&&</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"><</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">&&</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"><</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">&&</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):
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<arguments.length;t++){var n,o=arguments[t];for(n in o)Object.prototype.hasOwnProperty.call(o,n)&&(r[n]=o[n])}return r}
|
2205 |
function n(){return Object.assign&&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<f.length;u++)r=f[u],0<=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<l.length;o++)t=l[o],0<=r.indexOf(t)||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols)for(var l=Object.getOwnPropertySymbols(e),o=0;o<l.length;o++)t=l[o],0<=r.indexOf(t)||Object.prototype.propertyIsEnumerable.call(e,t)&&(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&gt;n.length)&&(r=n.length);for(var e=0,l=new Array(r);e<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&&"object"==typeof t&&"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&&(r=Object.getOwnPropertySymbols(t),e&&(r=r.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,r)),n}
|
49 |
function(e){var t;"default"!==e&&(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<"u"&&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)&&(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&&"object"==typeof r&&"default"in r?r:(n=Object.create(null),r&&Object.keys(r).forEach(function(e){var t;"default"!==e&&(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&&"function"==typeof Symbol&&o.constructor===Symbol&&o!==Symbol.prototype?"symbol":typeof o}
|
38 |
function(r){var n;return r&&r.__esModule?r:(n=Object.create(null),r&&Object.keys(r).forEach(function(e){var t;"default"!==e&&(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<"u"&&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)&&(f.push(e.value),f.length!==r);i=!0);}catch(l){o=!0,n=l}finally{try{if(!i&&null!=t.return&&(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<"u"&&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)&&(t[n]=o[n])}))(t,o)};return function(t,o){if("function"!=typeof o&&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)&&(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<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&&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<arguments.length;t++){var n,o=arguments[t];for(n in o)Object.prototype.hasOwnProperty.call(o,n)&&(r[n]=o[n])}return r}
|
2205 | spread operator? |
function n(){return Object.assign&&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<f.length;u++)r=f[u],0<=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<l.length;o++)t=l[o],0<=r.indexOf(t)||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols)for(var l=Object.getOwnPropertySymbols(e),o=0;o<l.length;o++)t=l[o],0<=r.indexOf(t)||Object.prototype.propertyIsEnumerable.call(e,t)&&(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)&&(r=n.length);for(var e=0,l=new Array(r);e<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&&"object"==typeof t&&"default"in t?t:{default:t}}
|
76 | ? |
function(t,e){var r,n=Object.keys(t);return Object.getOwnPropertySymbols&&(r=Object.getOwnPropertySymbols(t),e&&(r=r.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,r)),n}
|
49 | ? |
function(e){var t;"default"!==e&&(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<"u"&&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)&&(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&&"object"==typeof r&&"default"in r?r:(n=Object.create(null),r&&Object.keys(r).forEach(function(e){var t;"default"!==e&&(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&&"function"==typeof Symbol&&o.constructor===Symbol&&o!==Symbol.prototype?"symbol":typeof o}
|
38 | ? |
function(r){var n;return r&&r.__esModule?r:(n=Object.create(null),r&&Object.keys(r).forEach(function(e){var t;"default"!==e&&(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<"u"&&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)&&(f.push(e.value),f.length!==r);i=!0);}catch(l){o=!0,n=l}finally{try{if(!i&&null!=t.return&&(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<"u"&&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)&&(t[n]=o[n])}))(t,o)};return function(t,o){if("function"!=typeof o&&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)&&(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&&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<arguments.length;t++){var n,o=arguments[t];for(n in o)Object.prototype.hasOwnProperty.call(o,n)&&(r[n]=o[n])}return r}
|
2216 |
function n(){return Object.assign&&Object.assign.bind(),n.apply(this,arguments)}
|
1204 |
function n(){return Object.assign,n.apply(this,arguments)}
|
1010 |
function(){}
|
844 |
function(t){return t&&"object"==typeof t&&"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<f.length;u++)r=f[u],0<=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<l.length;o++)t=l[o],0<=r.indexOf(t)||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols)for(var l=Object.getOwnPropertySymbols(e),o=0;o<l.length;o++)t=l[o],0<=r.indexOf(t)||Object.prototype.propertyIsEnumerable.call(e,t)&&(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)&&(r=n.length);for(var e=0,l=new Array(r);e<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&&(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&&r.__esModule?r:(n=Object.create(null),r&&Object.keys(r).forEach(function(e){var t;"default"!==e&&(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&&"function"==typeof Symbol&&o.constructor===Symbol&&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&&(r=Object.getOwnPropertySymbols(t),e&&(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&&"object"==typeof r&&"default"in r?r:(n=Object.create(null),r&&Object.keys(r).forEach(function(e){var t;"default"!==e&&(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<"u"&&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<"u"&&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)&&(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<"u"&&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)&&(f.push(e.value),f.length!==r);i=!0);}catch(l){o=!0,n=l}finally{try{if(!i&&null!=t.return&&(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))&&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))&&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&&n instanceof Array}
|
21 |
function(r){if(Array.isArray(r))return P(r)}
|
21 |
function(e){return e&&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))&&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&&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<arguments.length;t++){var n,o=arguments[t];for(n in o)Object.prototype.hasOwnProperty.call(o,n)&&(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<f.length;u++)r=f[u],0<=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<l.length;o++)t=l[o],0<=r.indexOf(t)||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols)for(var l=Object.getOwnPropertySymbols(e),o=0;o<l.length;o++)t=l[o],0<=r.indexOf(t)||Object.prototype.propertyIsEnumerable.call(e,t)&&(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)&&(r=n.length);for(var e=0,l=new Array(r);e<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&&(r=Object.getOwnPropertySymbols(t),e&&(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&&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)&&(i.push(e.value),i.length!==r);a=!0);}catch(l){o=!0,n=l}finally{try{if(!a&&null!=t.return&&(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&&"function"==typeof Symbol&&o.constructor===Symbol&&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&&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<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:
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"><</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">&&</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">&&</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">&&</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"><</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">&</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">.&</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">&&</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">&&</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">&&</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">&&</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">&&</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"><</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"><=</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">&&</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">&&</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">&&</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">&&</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"><</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"><</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"><</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"><</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:
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"><</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">&&</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"><</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">&&</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:
$z=function n(){return Object.assign,n.apply(this,arguments)}
$q=function n(){return n=Object.assign&&Object.assign.bind(),n.apply(this,arguments)}
$FnName.prototype.something = somethingElse;
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">&&</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">&&</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">&&</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">&&</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">&&</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"> &&</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">&&</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 && 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:
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:
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"><</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.
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"><-</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"><-</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"><$></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> null </span><span style="color:#179299;--shiki-dark:#81C8BE"><$></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"><$></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"><-</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"><$></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 <$> 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"><&></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"><-</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"><&></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"><-</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"><-</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"><$></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> null </span><span style="color:#179299;--shiki-dark:#81C8BE"><$></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"><$></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"><-</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"><-</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"><$></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> <$></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"><&></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE"><&></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"><-</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"><-</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 <$> 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:
IO
monad
Maybe
monad
readDoc
calls (bear in mind: it is supposed to be a network call + document parse, so quite a heavy function)
My suggestions on how to make their code better:
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)
Maybe Bool
- in the functions where the
Maybe Bool
is used (
isTitleNonEmpty
and its variations)
just
Bool
would suffice
readDoc
once and use the result down the pipeline, no need to call it multiple times
(
readAndBuildSummary
,
readWhetherTitleNonEmpty
)
if
statements to guard expressions
case eitherValue
expressions with the
either
function
readWhetherTitleNonEmpty'
,
readWhetherTitleNonEmpty''
and
readWhetherTitleNonEmpty'''
)
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"><-</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"><-</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"><-</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"><-</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"><-</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"><-</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"><-</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"><-</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>
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"><-</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>
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"><-</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"><-</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"><-</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"><-</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"><-</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 & 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>
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>
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"><-</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"><-</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>
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"><-</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>
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:
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] < 0
for edge
j -> i
,
G[i][j] = 0
for no edge between vertices
i
and
j
)
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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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>
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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"><-</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"><-</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"><-</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"><-</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"><-</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"><-</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"><-</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.
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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"> &&</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"><-</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"><-</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"><-</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"><-</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"><-</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"><-</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"><-</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).
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 <|> 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 <*> 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"><|></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"><|></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"> <*></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"> <*></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"><|></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>
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:
<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>
<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
<$>
to combine it with other functions:
<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"><$></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>
<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"> <$></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"> <*></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"> <$></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"> <$></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"> <*></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
<$>
, 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"> <*></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
<*>
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
<|>
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"> <$></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> read </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:#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"><$></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"><|></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>
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"><-</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"><-</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"><-</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"><-</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"><-</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"><|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> negativeSign </span><span style="color:#179299;--shiki-dark:#81C8BE"><|></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"><-</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"><-</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 .
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" // <--- 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.
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" // <--- 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.
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.
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"> <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"> <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" // <--- 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">&</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">&</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">&</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">&</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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Parse Tree: "</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:#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))) }))) }) <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"><</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"><</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 <variant>
#include <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<ObjectValueContext*>(_localctx->parent)->propertyMap[$name] = $value; }
;
propertyValue
: intVector { antlrcpp::downCast<PropertyContext*>(_localctx->parent)->value = $intVector.elements; }
| floatVector { antlrcpp::downCast<PropertyContext*>(_localctx->parent)->value = $floatVector.elements; }
| INT { antlrcpp::downCast<PropertyContext*>(_localctx->parent)->value = std::stoi($INT.text); }
| FLOAT { antlrcpp::downCast<PropertyContext*>(_localctx->parent)->value = std::stof($FLOAT.text); }
| BOOL { antlrcpp::downCast<PropertyContext*>(_localctx->parent)->value = static_cast<bool>($BOOL.text == "true"); }
| STRING { antlrcpp::downCast<PropertyContext*>(_localctx->parent)->value = $STRING.text; }
| objectValue { antlrcpp::downCast<PropertyContext*>(_localctx->parent)->value = $objectValue.propertyMap; }
;
objectValue
returns [
std::string classifier,
std::map<std::string, std::any> propertyMap
]
: '{' property* '}'
| STRING '{' (property)* '}' { $classifier = $STRING.text; }
;
intVector
returns [ std::vector<int> elements ]
: INT+ { auto v = $ctx->INT(); std::for_each(v.begin(), v.end(), [&](auto* node) { _localctx->elements.push_back(std::stoi(node->getText())); }); }
;
floatVector
returns [ std::vector<float> elements ]
: FLOAT+ { auto v = $ctx->FLOAT(); std::for_each(v.begin(), v.end(), [&](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"><</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<PropertyContext*>(_localctx->parent)->value = $intVector.elements; }
| floatVector { antlrcpp::downCast<PropertyContext*>(_localctx->parent)->value = $floatVector.elements; }
| INT { antlrcpp::downCast<PropertyContext*>(_localctx->parent)->value = std::stoi($INT.text); }
| FLOAT { antlrcpp::downCast<PropertyContext*>(_localctx->parent)->value = std::stof($FLOAT.text); }
| BOOL { antlrcpp::downCast<PropertyContext*>(_localctx->parent)->value = static_cast<bool>($BOOL.text == "true"); }
| STRING { antlrcpp::downCast<PropertyContext*>(_localctx->parent)->value = $STRING.text; }
| objectValue { antlrcpp::downCast<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<int> elements ]
: INT+ { auto v = $ctx->INT(); std::for_each(v.begin(), v.end(), [&](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<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<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"> <iostream></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <map></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <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"> <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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "(str){ "</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"><</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"> <<</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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "(int){ "</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"><</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"> <<</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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "(float){ "</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"><</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"> <<</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"><</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"><</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"><</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"><<</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"><<</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val </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:#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"><<</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"><</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"><</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"><</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"><<</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"><<</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val </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:#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"><<</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"><</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"><</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"><</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"><<</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">&</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"><<</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"><<</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"><<</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" // <--- 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">&</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">&</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">&</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">&</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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Parse Tree: "</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:#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"><</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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Objects found: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> <<</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"> <<</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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "["</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:#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>
<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">&</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"><<</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"><<</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"><<</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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " } "</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:#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.
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):
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 .
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):
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 .
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.
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.
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) .
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"> <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>
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:
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"> <fstream></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <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"> <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"> <globjects/Buffer.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <globjects/Error.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <globjects/Program.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <globjects/Shader.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <globjects/VertexArray.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <globjects/VertexAttributeBinding.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <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"> <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"> <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"> <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"> <SFML/OpenGL.hpp></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <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">&</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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[DEBUG] "</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">message</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:#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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[INFO] Initializing..."</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:#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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[INFO] Creating shaders..."</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:#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"><<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "done"</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:#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"><<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "done"</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:#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"><<</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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "done"</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:#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"><<</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "done"</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:#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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[INFO] Done initializing"</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:#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<</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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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>
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"> <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"> <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"> <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"> <glm/mat4x4.hpp></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <glm/vec2.hpp></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <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<</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"><</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<</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<</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<</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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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>
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"><</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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>
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.
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"><</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"><</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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"><</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"><</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">&</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">&</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"><</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<</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"><</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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:
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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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>
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"><</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><<</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"> <<</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><<</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"> <<</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><<</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"> <<</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"><</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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"><</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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"><</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>
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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><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<</span><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<</span><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<</span><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<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<</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<</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<</span><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<</span><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<</span><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<</span><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.
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"><</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, 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"><=</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"><=</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"><</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 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"><=</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>
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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[ERROR] Can not compile vertex shader"</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:#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"><</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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[ERROR] Can not compile geometry shader"</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:#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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[ERROR] Can not compile fragment shader"</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:#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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[ERROR] Can not compile chicken fragment shader"</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:#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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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.
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.
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>
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"><</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>
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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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"><</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"><</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<</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<</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"><</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"><</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"> &</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"> &</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 & 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<</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<</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<</span><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<</span><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<</span><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<</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</span><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<</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<</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"><</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</span><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<</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<</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<</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<gl::ClearBufferMask>(GL_COLOR_BUFFER_BIT), static_cast<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"><</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<</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<</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<</span><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<</span><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<</span><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<</span><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"><</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"> <</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"><</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"><</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"><</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.
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"><</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"><</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>
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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</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<</span><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<</span><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<</span><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<</span><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"><</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"> &&</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:#4C4F69;--shiki-dark:#C6D0F5"> thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE"><</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>
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 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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><=</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"><=</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</span><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<</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<</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"><</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</span><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<</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<</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<</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<gl::ClearBufferMask>(GL_COLOR_BUFFER_BIT), static_cast<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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</span><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<</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<</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"><</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</span><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<</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<</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<</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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"><</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"><</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"><</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"><</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 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:
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"><</span><span style="color:#DF8E1D;--shiki-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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</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">&</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">&</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<</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</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<</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><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<</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<</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<</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><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<</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><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<</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"><</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"><</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"><</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"><</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>
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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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"><</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<</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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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"><</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 < 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 < 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"> <</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 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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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<</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><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"><</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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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<</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><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"><</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"><</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>
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:
Pet { name: string, kind: enum Kind { CAT, DOG } }
StringIdsResource { ids: string[] }
StringIdsResource { ids: int[] }
As mentioned before, the metrics I'm going to be focusing on are:
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:
My take on these results is that:
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.
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:
Pet { name: string, kind: enum Kind { CAT, DOG } }
StringIdsResource { ids: string[] }
StringIdsResource { ids: int[] }
As mentioned before, the metrics I'm going to be focusing on are:
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:
My take on these results is that:
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.
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:
Amongst technologies covered here, only three do not use data schema:
But the others, which do use schemas, need the schema to be compiled before it is used.
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"><</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 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 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 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>
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>
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.
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<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>
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:
<code>CBOR-encode: 0.779ms
CBOR-decode: 0.587ms
[CBOR]> pre-utf8 (25): <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]: <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>
<code>BSON-encode: 0.631ms
BSON-decode: 1.079ms
[BSON]> pre-utf8 (37): <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>
<code>MessagePack-encode: 0.738ms
MessagePack-decode: 0.664ms
[MessagePack]> pre-utf8 (25): <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]: <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:
<code>Avro-encode: 0.199ms
Avro-decode: 0.181ms
[Avro]> pre-utf8 (9): <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>
<code>Protobuf-encode: 2.723ms
Protobuf-decode: 0.231ms
[Protobuf]> pre-utf8 (11): <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.
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.
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).
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"><?</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"><</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"> <</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"> <</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"> <</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"> <</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"> </</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"> <</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"> <</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"> <</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"> <</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"> </</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"></</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
<item>
nodes and its
<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.
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"><?</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"><</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"> <</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"> <</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"> <</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"> <</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"> </</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"> <</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"> <</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"> <</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"> <</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"> </</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"></</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
<item>
nodes and its
<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"> `<?xml version="1.0" encoding="utf-8"?><items><item rank="1"><name value="Beyond the Sun"/></item></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"> `<?xml version="1.0" encoding="utf-8"?><items><item rank="1"><name value="Beyond the Sun"/></item></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 <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 <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 <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">'<?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 <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"> '<?xml version="1.0" encoding="utf-8"?><items><item rank="1"><name value="Beyond the Sun"/></item></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"> `<?xml version="1.0" encoding="utf-8"?><items><item rank="3"><name value="Beyond the Sun"/></item></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"><</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"><</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"><</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"><</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"><</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.
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:
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.
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
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:
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.
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<Game>
while
extractGames
returns just that -
Array<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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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">&&</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"><</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"><</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">&&</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"><</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"> <</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"> <</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"><</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"><</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"> <</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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"> <</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"><</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"><</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"> <</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"><</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"><</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"> <</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"> <</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"> <</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"><</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"><</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"> <</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"><</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"><</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"><</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"> <</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"> <</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"> <</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"> <</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"> <</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"><</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"><</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"> <</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"><</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"><</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"><</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"> <</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"><</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"><</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"> <</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"><</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"><</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"> <</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"> <</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"> <</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"> <</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"> <</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"> <</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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<Game>
, but the
extractGames
function should return an
Either<Error, Array<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"><</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"><</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"><</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<T>
to
Either<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<?>
and for
Some<A>
we could return
Right<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"> <</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"> <</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"><</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"><</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"> <</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"><</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"><</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"><</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"> <</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"> <</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"> <</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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"> <</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"><</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"><</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"> <</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"><</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"><</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"> <</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"> <</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"> <</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"> <</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"> <</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"> <</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"> <</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"><</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"> <</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"> <</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"><</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"><</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"> <</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"><</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"><</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"> <</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"> <</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"> <</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"> <</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"> <</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"> <</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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<Error, XMLDocument>' is not assignable to parameter of type 'XMLDocument'.
Type 'Either<Error, XMLDocument>' is missing the following properties from type 'XMLDocument': addEventListener, removeEventListener, URL, alinkColor, and 247 more.
Argument of type 'Either<Error, Game[]>' is not assignable to parameter of type 'Game[]'.
Type 'Either<Error, Game[]>' is missing the following properties from type 'Game[]': length, pop, push, concat, and 25 more.
Argument of type 'Either<Error, Game>' is not assignable to parameter of type 'Game'.
Type 'Either<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<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<Error, XMLDocument> ~> PromiseIO<Either<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<Error, XMLDocument> -> extractGames(Array<Game>): Either<Error, Array<Game>> ~> PromiseIO<Either<Error, Array<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<Error, Array<Game>> -> getRandomTop10Game(Array<Game>): Either<Error, Game> ~> PromiseIO<Either<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<Error, Game> -> printGame(Game): void ~> PromiseIO<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<Either<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<Either<Error, XMLDocument>></span></span></code>
Let's recall how the method
map
on
PromiseIO<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"><</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"><</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"><</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"><</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<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"><</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"><</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<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 -
<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"> <</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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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<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"><</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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<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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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<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"><</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"><</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"><</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"><</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"><</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"><</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"><</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<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<A>.then((a: A) => func(a)) => Promise<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<B></span></span></code>
But since the function
func
returns
PromiseIO<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<A, PromiseIO<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<A>.then((a: A) => func(a)) => Promise<PromiseIO<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<PromiseIO<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<A>.then(() => Promise<B>)
resolves in
Promise<B>
.
We can utilize this property of
Promise
, if the function we wrap will return
Promise<Promise<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"><</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"><</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"><</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<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<PromiseIO<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"><</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"><</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"><</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"><</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<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<Promise<B>>, which is automatically converted to Promise<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<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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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<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<ExceptionW<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<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<ExceptionW<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<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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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<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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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<Wrappable<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<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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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<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<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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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>
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<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"><</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"><</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"><</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"><</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"><</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<A>
which would return a
Maybe<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"><</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"><</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"><</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"><</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"><</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<Error>
with a message
rather than some misleading exception (with a stack trace, though).
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:
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"> <</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"><</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"> <</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"><</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"><</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"><</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"> <</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"><</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"><</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"> <</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"> <</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"> <</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"> <</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"> <</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"> <</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"><</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"><</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"><</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"><</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"><</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!
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 <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 <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!
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:
get(<key>)
- get key value
set(<key>)
- use request body for value and associate the value with the key
delete(<key>)
- remove the key from the storage
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).
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)
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
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.
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>
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>
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 .
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"> <</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"><</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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"><</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"> <</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"><</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"><</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"> <</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"> <</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"><</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"><</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"> <</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"> <</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"><</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"><</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"><</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"><</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>
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<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).
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.
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:
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.
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.
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:
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.
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 algorithm... worked... in some cases:
I did try to understand the concept of barycentric coordinates, but that is something completely different to what I imagined, apparently:
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).
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
AB <=> a(ax, ay, az)
AC <=> b(bx, by, bz)
AP <=> 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 .
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:
In this blog I describe in bloody detail what I do and why.
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:
In this blog I describe in bloody detail what I do and why.
First of all, applicaiton structure is:
main.cpp
- only instantiates the
Application
class and calls its
run()
method (the only public API of the
Application
class)
Application
class - has two purposes:
ApplicationDelegate
class
ApplicaitonDelegate
- does a bit more than
Application
:
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.
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.
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 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>
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>
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"> <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"><</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"><</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"> <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"> <iostream></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <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"><</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"><</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"><</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"><<</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"><</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"><</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"> <fstream></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <iostream></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <memory></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <queue></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <sstream></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <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"> <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">&</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">&</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">&</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">&</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"><</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):
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:
After:
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"> <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"> <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"><</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">&</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"><</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"><</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">&</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">&&</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>
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 $<TARGET_FILE_DIR:${EXECUTABLE_NAME}>/media)</span></span></code>
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"> <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"> <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"> <memory></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <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"> <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">&</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">&</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">&</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">&</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">&</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">&</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">&</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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">&</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">&</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">&</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">&</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">&</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">&&</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">&&</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"><</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"><</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"><</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"><</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"> &</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"> &</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">&</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">&</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"><</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"><</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"><</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>
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.
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.
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:
The issues I see with TypeScript and Flow are bit closer to the real world:
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?
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"><</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">&&</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">&&</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"><</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"><</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>
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"><</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<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"><</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<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>
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"><</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"><</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"><</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"><</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"><</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"><</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"> <</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"> <</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"> <</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"></</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"> (<</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"></</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"> </</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"> <</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"> <</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"></</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"> <</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"> </</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"> </</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:
TypeError: AREA[shape] is not a function
will be thrown
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<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"><</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.
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>
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:
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.
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?
(Heavily over-opinionated statement) Elm forces you to handle error scenarios when writing the code.
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>
(Heavily over-opinionated statement) Elm forces you to handle error scenarios when writing the code.
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 <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.
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"><-</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"><-</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"><-</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"><-</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"><-</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"><$></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"><$></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>
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"><-</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"><-</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"><-</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"><-</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"><-</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"><$></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"><$></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"><-</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"><-</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"><-</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"><-</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"><-</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 "<-" 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 } <- 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
<>
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 <- 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"><-</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"><-</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"> <></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"><-</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"><-</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"><-</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, ($), (*), (<>))
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"><!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"><</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"><</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"> <</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"> <</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"> <</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"></</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"></</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"><</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"> <</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"><</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"></</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"></</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"> &&</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"><-</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"><-</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"><-</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 .
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);
<div>
<p> {React.string(name ++ " clicked " ++ string_of_int(count) ++ " times")} </p>
<button onClick={_ => setCount(_ => count + 1)}>
{React.string("Click me")}
</button>
</div>
};
};
ReactDOMRe.renderToElementWithId(<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);
<div>
<select>
<option value=""> Choose shape </option>
<option value="circle"> Circle </option>
<option value="square"> Square </option>
</select>
<input value={value} />
<p> {React.string(string_of_float(area))} </p>
<button>
{React.string("Calculate")}
</button>
</div>
};
</code>
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);
<div>
<p> {React.string(name ++ " clicked " ++ string_of_int(count) ++ " times")} </p>
<button onClick={_ => setCount(_ => count + 1)}>
{React.string("Click me")}
</button>
</div>
};
};
ReactDOMRe.renderToElementWithId(<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);
<div>
<select>
<option value=""> Choose shape </option>
<option value="circle"> Circle </option>
<option value="square"> Square </option>
</select>
<input value={value} />
<p> {React.string(string_of_float(area))} </p>
<button>
{React.string("Calculate")}
</button>
</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"><</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"></</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);
<div>
<select>
<option value="">{React.string("Choose shape")}</option>
<option value="circle">{React.string("Circle")}</option>
<option value="square">{React.string("Square")}</option>
</select>
<input value={value} />
<p> {"Area:" ++ React.string(string_of_float(area))} </p>
<button>
{React.string("Calculate")}
</button>
</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"><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"><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"><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:
< .. > 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"><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"><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"><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"><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<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<type>
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
};
<div>
<select onChange={ event => {
// the issue with event.target.value is somewhat resolved
let v: string = ReactEvent.Form.target(event)["value"];
setShape(_ => shapeChanged(v))
}}>
<option value="">{React.string("Choose shape")}</option>
<option value="circle">{React.string("Circle")}</option>
<option value="square">{React.string("Square")}</option>
</select>
<input value={Js.Float.toString(value)} onChange={ event => {
let v: string = ReactEvent.Form.target(event)["value"];
setValue(_ => float_of_string(v));
}} />
<p>{React.string("Area:" ++ Js.Float.toString(area))}</p>
<button onClick={ _ => {
setArea(_ => Belt.Option.mapWithDefault(_shape, 0.0, s => calculateArea(s, value)))
}}>
{React.string("Calculate")}
</button>
</div>
};
};
</code>
TL;DR:
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).
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"><</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<'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"><</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"><</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:
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:
<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>
<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>
<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"> (<#>)</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"><#></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"> <#></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"> <#></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"> (map (fromStringAs hexadecimal))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE"> <#></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>
<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"><</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>
<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>
<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.
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"><-</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"><-</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"><-</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"><-</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"> <></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"> " 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"><-</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"><-</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"><-</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"><-</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).
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:
<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>
<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>
<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"> (<#>)</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"><#></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"> <#></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"> <#></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"> (map (fromStringAs hexadecimal))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE"> <#></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>
<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"><</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>
<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>
<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.
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"><-</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"><-</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"><-</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"><-</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"> <></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"> " 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"><-</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"><-</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"><-</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"><-</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).
<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>
Here is a comparison of the test results:
| Tool | Test results |
|---|---|
| F# | ✅ |
| PureScript | ❌ |
| ReScript | ✅ |
| ScalaJS | ❌ |
| TypeScript | ❌ |
| Elm | n/a |
| Gleam | ✅ |
Some implementations still throw error when the data type is not what the function expects.
<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>
<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>
<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>
<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>
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.
| Tool | Bundle size |
|---|---|
| F# | 40K |
| PureScript | 174K |
| ReScript | 22K |
| ScalaJS | 197K |
| TypeScript | 1.4K |
| Elm | n/a |
| Gleam | 10.8K |
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.
I have been writing about and improving on my Gantt chart implementation for quite some time now.
It all started with this ( blog ):
Then I added few features ( blog ):
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:
Here, you can even play around with it now!
More about the implementation specifics under the cut.
I have been writing about and improving on my Gantt chart implementation for quite some time now.
It all started with this ( blog ):
Then I added few features ( blog ):
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:
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:
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.
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.
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.
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.
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.
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"><</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"> <</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"> <</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"></</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"> <</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"> <</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"> <</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"> </</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"> <</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"> <</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"> </</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"> <</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"> <</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"> </</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"> <!-- ... --></span></span> <span class="line"><span style="color:#179299;--shiki-dark:#81C8BE"> </</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"> </</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"></</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.
There are quite a few lessons that I have learned.
I freaking hate CMake for a few very good reasons:
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.
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:
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.
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"><</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"><</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"><</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"> <</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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "processing unknown action"</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:#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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "destroying an object"</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:#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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "playing a sound"</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:#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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "playing a sound"</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:#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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "destroying an object"</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:#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"><<</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "unknown action"</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:#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>
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.
This way you can have same handler for gamepad buttons' and keyboard/mouse input events:
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.
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:
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"?
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:
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!
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:
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:
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.
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"><</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"><</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"><</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>
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"><</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"><</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"><</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"><</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"><</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"><</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>
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.
Let's start with few simple but practical examples.
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.
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>
Using
Rebar 3
(or
Hex
for Elixir) is relatively easy. Yet it opens access to thousands of packages available out there.
To create a project with rebar3 support, you can now use
rebar3 new <template> <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 <comma-separated-app-names>
from the
project
root directory (e.g.
rebar3 shell --apps appname
).
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:
SELECT
,
INSERT
,
UPDATE
and
DELETE
statements (with very few exceptions, these form 95% of all the use cases, in my experience)
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>
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"> % <---- 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>
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.
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.
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<
to change the text surrounded with
<
and
>
ci{symbol}
to change the text surrounded by
symbol
, which could be
'
,
"
,
&#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
&gt;
and
&lt;
adds or removes the indentation
{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
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:
Apart from that, there are few technical challenges preventing his whole thing from becoming a real application component:
Now I want to revise the original implementation and make it a bit more usable, just like this:
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:
Apart from that, there are few technical challenges preventing his whole thing from becoming a real application component:
Now I want to revise the original implementation and make it a bit more usable, just like this:
The plan for this blog is:
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:
import
instead of
require()
const
over
let
and
var
Object.assign
with spread operator
null
and
undefined
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:
Let us actually start with D3.
The library currently operates on few features from D3:
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
.
Currently,
moment.js
is used for few purposes:
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.
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>
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>
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">&&</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">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>
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.
Welcome to a 5-minute Erlang introduction!
First things first:
erl
is the REPL shell
q().
to exit the shell
c(file_name).
to load the code from file
Now, to the language constructs:
.
) symbol
,
) character
'atoms are awesome'
@
)
fun() -> return_statement end.
end
must not
end with comma
function_name/number_of_arguments
:
factorial/1
,
format/2
%
) symbol
[ TheOnlyElement ]
or
[ Head | TailElements ]
, where
TailElements
is also a list
[ Head1 | Head2 | Tails ] = [ 1, 2, 3, 4 ]
"strings"
{ elt1, elt2 }
#{ key => value }
<
(less than),
>
(greater than),
>=
(greater than or equals to),
=<
(equals to or less than),
==
(equals to),
/=
(not equals to),
=:=
(adds type checking on tops, JS equivalent of
===
)
=
+
,
-
,
*
,
/
,
div
,
rem
(Pascal way)
is_atom/1
,
is_function/1
,
is_number/1
,
is_boolean/1
,
is_pid/1
,
is_list/1
, etc.
[ N || N <- [ 1, 2, 3, 4, 5 ], N rem 2 == 0 ].
-module(module_name).
-export([ list_of_function_signatures ]).
-import(module_name, [ list_of_functions ]).
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">=<</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">=<</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"><-</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).
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.
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):
<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"><</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>
<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>
<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"><</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.
<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 && 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 && 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>
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 && 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 && 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>
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.
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!
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"><</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"><</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"><</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"><</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 <>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 <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"><>f__AnonymousType0<User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Token> <>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"> <></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 <>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"> <>c <>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"><></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<User, string> <>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<Token, string> <>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<User, Token, <>f__AnonymousType0<User, Token>> <>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<<>f__AnonymousType0<User, Token>, User> <>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 <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 <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"> <>f__AnonymousType0<User, Token> <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"><></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"><</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 <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"><>f__AnonymousType0<User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Token> <>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"> <></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"> <></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c__DisplayClass2_0 </span><span style="color:#179299;--shiki-dark:#81C8BE"><></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"><></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"> <></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"> <></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">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"><></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">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"><</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"><></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE"><></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"><</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"> <></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">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"><></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">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"><</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"><></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE"><></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"><</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"> <></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">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"><></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">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"><</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"> <></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"><</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"><></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE"><></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"><</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"><<></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"><</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"><></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">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"> <></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">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"><></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">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"><<></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"><</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"><></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE"><></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"><</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"> <></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c__DisplayClass2_0 </span><span style="color:#179299;--shiki-dark:#81C8BE"><></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"><></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"> <></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"> <></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">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"><></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">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"><</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"><></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE"><></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"><</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"> <></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">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"><></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">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"><</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"><></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE"><></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"><</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"> <></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">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"><></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">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"><</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"> <></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"><</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"><></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE"><></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"><</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"><<></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"><</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"><></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">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"> <></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">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"><></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">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"><<></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"><</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"><></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE"><></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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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 <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 <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<User, Token> <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"><</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 <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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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<{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<{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<{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<Weirdo>.UserId was accessed Token<Waldo>.UserId was accessed User<1001>.Id was accessed Token<Waldo>.Body was accessed User<1002>.Id was accessed Token<Weirdo>.Body was accessed User<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<Weirdo>.UserId was accessed Token<Waldo>.UserId was accessed User<1001>.Id was accessed Token<Waldo>.Body was accessed User<1002>.Id was accessed Token<Weirdo>.Body was accessed User<1006>.Id was accessed User<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<Weirdo>.UserId was accessed Token<Waldo>.UserId was accessed Token<Quattro>.UserId was accessed User<1001>.Id was accessed Token<Waldo>.Body was accessed User<1002>.Id was accessed Token<Weirdo>.Body was accessed User<1006>.Id was accessed User<1008>.Id was accessed Token<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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><</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"><></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"><</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"><</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"><</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"><</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"><</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"><</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"><></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"><</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"><</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"><</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"><></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"><</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"><</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"><</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"><</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"><></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"><</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"><</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"><</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"><></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"><</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"><</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"><></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"><</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"><</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"><</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"><></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"><</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"><</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"><</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"><></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"><</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"><</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"><></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"><</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">&&</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"><</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"><</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">&&</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<Weirdo>.UserId was accessed User<1001>.Id was accessed Token<Waldo>.UserId was accessed User<1001>.Id was accessed Token<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"><</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"><</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"><</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"><</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<1001>.Id was accessed User<1002>.Id was accessed User<1006>.Id was accessed User<1008>.Id was accessed Token<Weirdo>.Body was accessed Token<Weirdo>.UserId was accessed Token<Waldo>.Body was accessed Token<Waldo>.UserId was accessed Token<Quattro>.Body was accessed Token<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.
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"><</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>
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<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
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) :
The things which are already done (just not published yet), in progress and the future plans for this tutorial include:
Tutorial chapters (yet to be updated) :
<code> <li>
<a href="/irrlicht-newton-tutorials/2015/08/26/application-architecture.html">
Application architecture
</a>
</li>
<li>
<a href="/irrlicht-newton-tutorials/2015/08/27/first-application.html">
First application
</a>
</li>
<li>
<a href="/irrlicht-newton-tutorials/2015/08/28/first-script.html">
First script
</a>
</li>
<li>
<a href="/irrlicht-newton-tutorials/2015/08/29/prepare-to-add-some-newtonianity.html">
Let's add some physics
</a>
</li>
<li>
<a href="/irrlicht-newton-tutorials/2015/12/15/making-simple-level-with-blender.html">
Modelling simple level with Blender3D
</a>
</li>
<li>
<a href="/irrlicht-newton-tutorials/2015/12/16/finishing-the-first-scene.html">
Finishing the first scene
</a>
</li>
</ul>
</code>
Under the cut you can find the interesting algorithmic solutions I've mentioned.
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">&&</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"><</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"><</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"><</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>
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"><</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"><</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"><</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.
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>
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"> &&</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"> &&</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"> &&</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"> &&</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 && '</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?
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.
In essence, processor consists of these main blocks:
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.
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.
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.
In essence, processor consists of these main blocks:
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.
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.
Each processor instruction is a chain of ones and zeros. Assume we have these commands processor can understand:
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")
Let us name these commands:
ADD
= A + B -> C
SUB
= A - B -> C
MUL
= A * B -> C
DIV
= A / B -> C
NOTA
= NOT A
NOTB
= NOT B
AND
= A AND B -> C
OR
= A OR B -> C
XOR
= A XOR B -> C
SHR
= A >> B -> C (bitwise shift right)
SHL
= A << B -> C (bitwise shift left)
MOV A, const
= const -> A
MOV B, const
= const -> B
MOV C, A
= C -> A
MOV C, B
= C -> B
MOV A, C
= A -> C
MOV B, C
= B -> C
LOAD addr, A
= memory[addr] -> A
LOAD addr, B
= memory[addr] -> B
LOADB
= memory[A] -> B
SAVEB
= B -> memory[A]
CMP
= A <=> B -> C
JMP line
= GOTO line
JL line
= if A < B (from comparison flags in C) then GOTO line
JLE line
= if A <= B then GOTO line
JEQ line
= if A == B then GOTO line
JNEQ line
= if A != B then GOTO line
JGE line
= if A >= B then GOTO line
JG line
= if A > B then GOTO line
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:
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"><</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:
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: <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 <=> 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 <=> 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 = &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] <=> 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 = &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] <=> 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 <=> 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 <=> 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 <=> 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 <=> C = &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] <=> 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 <=> 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 = &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 <=> result = B <=> 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 <=> 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 <=> 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 = &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 <=> i = B <=> 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.
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 << 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
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!
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!
<code><div><kbd>Cmd+1</kbd> .. <kbd>Cmd+9</kbd></div>
<div>
To go back to editor - just hit <kbd>Esc</kbd> <br />
Project Tree: <br />
<video preload autoplay loop muted>
<source src="/images/intellij-performance-tips/cmd_1_esc.webm" />
<source src="/images/intellij-performance-tips/cmd_1_esc.webp" />
</video>
<br />
Search results:
<br />
<video preload autoplay loop muted>
<source src="/images/intellij-performance-tips/cmd_3_esc.webm" />
<source src="/images/intellij-performance-tips/cmd_3_esc.webp" />
</video>
<br />
Version Control:
<br />
<video preload autoplay loop muted>
<source src="/images/intellij-performance-tips/cmd_9_esc.webm" />
<source src="/images/intellij-performance-tips/cmd_9_esc.webp" />
</video>
</div>
</code>
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.
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.
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"><</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"><</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"><</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.
There is a revised version of this blog , showing how an algorithm implementation could be optimized.
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!
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:
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)
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
?
There is a revised version of this blog , showing how an algorithm implementation could be optimized.
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!
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:
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)
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
?
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"><</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"><</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>
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"><</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"><</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"><</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"><</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"><</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:
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
u
to
u
is thought to be infinitely long meaning we do not allow this type of paths
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 | |
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 | |
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:
3 -> 0
does not exist (
inf
)
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
:
3
to
2
directly, so its length is
inf
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 | |
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 | |
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
:
0
to
1
does not exist, take it as
inf
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
:
2 -> 0
does not exist
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
:
2 -> 1
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.
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"><</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"><</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
:
start = 0, end = 1
R[0, 1] == 2, start = 2, end = 1
R[2, 1] == 3, start = 3, end = 1
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
.
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"><</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"><</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"><</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"><</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"><</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"> <</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"><</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"><</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"><</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"><</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"><</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
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.
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)orO(log(n)).
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.
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)orO(log(n)).
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"><</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"><</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"><</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:
n
is
1
, both part 2 and part 3 take
C
steps
n
is
3
, part 2 takes
3*C
steps while part 3 takes
9*C
steps
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)
.
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) < O(log(n)) < O(n) < O(n * log(n)) < O(n^2) </code>
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.
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)
.
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:
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.
There are few updates to this original implementation in my new blog .
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:
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.
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:
endDate
end of a parent element and near
startDate
end of children element)
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">&&</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">&&</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:#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">&&</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> endDate </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:#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"><</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">&&</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"> 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"> <<</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">&&</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">&&</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">&&</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">&&</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:
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.
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 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:
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.
My implementation contains several core elements:
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.
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.
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"><</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"> <</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"></</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">&&</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">&&</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">&&</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">&&</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:
RenderingParams
Now, tiles should be rotated. To do that, two tricks have been applied:
UIImage
, we can simply rotate that image around its center to create the visual effect of rotation
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:
(0, 0)
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.
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">&&</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">&&</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>
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 of this coding exercise looks like exactly as the one at the very top of this post:
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:
What's hidden beneath the next version of the library?
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:
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:
VirtualDOMNode
class
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)
.
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 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
I hope this library is a little bit more than just an experiment and once it will be used for a great good!
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.
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.
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"><</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>
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"><</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>
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:
64 bits
MM0
..
MM7
SSE highlights:
SSE2 features:
XMM0
..
XMM15
)
SSE3 changes:
SSE4 advantages:
AVX - brand new version:
256 bit
YMMi
, while
XMMi
are the lower 128 bits of
YMMi
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:
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:
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:
__m128
, which is SSE’s
float[4]
__m128d
corresponds to
double[2]
__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:
_mm_set_ps(4.0, 3.0, 2.0, 1.0)
->
[4.0, 3.0, 2.0, 1.0]
_mm_set1_ps(3.0)
->
[3.0, 3.0, 3.0, 3.0]
_mm_set_ss(4.0)
->
[0.0, 0.0, 0.0, 4.0]
_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]
)
:
_mm_store_ps(float[4], __m128)
->
[4.0, 3.0, 2.0, 1.0]
_mm_store_ss(float*, __m128)
->
1
_mm_store_ss(float*, __m128)
->
[1.0, 1.0, 1.0, 1.0]
double _mm_cvtsd_f64(__m128d)
->
1
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"><</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">&</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 << 6) | (y << 4) | (x << 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) << 6) | (m2(y) << 4) | (m1(x) << 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"><</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 << 6) | (1 << 4) | (0 << 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"><</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"><</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">&</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"><</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"><</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
!).
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"><</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"><</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">&</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"><</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">&</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"><</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!
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) .
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.
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.
<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"> <</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"> <</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"></</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"> <</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"></</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"> <</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"></</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"> </</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"><</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>
<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"> <</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"> <</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"></</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"> <</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"></</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"> <</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"></</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"> </</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"><</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><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>
<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><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><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>
Let's start-off by writing a simple "counter" application with the well-known React + Redux bundle.
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"> <</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"> <</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"></</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"> <</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"></</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"> <</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"><</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"> <</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"><</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>
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:
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"> <</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"> <</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"></</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"> <</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"></</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"> <</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"></</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"> </</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"><</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>
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:
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 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>
This is much less code than in case with React + Redux, isn't it?
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>
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.
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:
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.
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>
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
:
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)
['div', { 'ng-repeat': 'item in items' }, '{{item.name}}']
properties
and
children or text
arguments are optional; thus you can create empty DOM elements:
['hr']
createApplication()
function, has the
dispatch(message)
method
In later posts I'll provide more examples of using
libc
.
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.
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">&&</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">&&</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>
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>
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>
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 & 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">& 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"><</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>
<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>
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>
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...
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"><</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"><</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"><</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"><</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) < O(log n) < O(n) < O(n*log n) < 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"><</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)
.
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) :
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.
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><div class="col-xs-12 col-md-3">
<a href="/images/two-sides-of-web-application/part1/screen2.webp">
<img src="/images/two-sides-of-web-application/part1/screen2.webp" loading="lazy" alt="page 2" class="image-responsive">
</a>
</div>
<div class="col-xs-12 col-md-3">
<a href="/images/two-sides-of-web-application/part1/screen3.webp">
<img src="/images/two-sides-of-web-application/part1/screen3.webp" loading="lazy" alt="page 3" class="image-responsive">
</a>
</div>
<div class="col-xs-12 col-md-3">
<a href="/images/two-sides-of-web-application/part1/screen4.webp">
<img src="/images/two-sides-of-web-application/part1/screen4.webp" loading="lazy" alt="page 4" class="image-responsive">
</a>
</div>
</code>
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:
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.
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.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:
Let's start and you will see how easy it is!
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:
<html>
tag with
ng-app
directive
Yeah, we definitely need some clarifications about those two new words.
Angular defines a few kind of bricks, you may use to build an entire application:
On the other hand, in MVVM architecture we have three layers:
Accordingly to this scheme, in Angular we have the next logic structure:
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.
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
<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
<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"><</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"></</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.
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.
See the Pen Simple web analytics. Angular injection. v1 by Artem Shoobovych ( @shybovycha ) on CodePen .
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!
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.
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!
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.
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>
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:
resolve
attribute for the
$routeProvider.when()
method
$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"> &&</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">&&</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>
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 .
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
Box
Cone
Capsule
Cylinder
Chamfer Cylinder
Convex Hull
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):
A bit better, but still the same situation with convex hull shape:
Generally, the way we create our Newtonian body is:
userData
property
And then Newton Game Dynamics will take your body into account when processing other objects
in the
NewtonWorld
.
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
Box
Cone
Capsule
Cylinder
Chamfer Cylinder
Convex Hull
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):
A bit better, but still the same situation with convex hull shape:
Generally, the way we create our Newtonian body is:
userData
property
And then Newton Game Dynamics will take your body into account when processing other objects
in the
NewtonWorld
.
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:
irr::video::S3DVertex
class in Irrlicht
irr::video::S3DVertex2TCoords
class
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"><</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"> &</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"><</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"> &</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"> &</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"> &</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"> &</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"> &</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:
massMatrix
, which determines how the mass is spread along the body
transformCallback
and
forceAndTorqueCallback
are two mandatory fields, required by Newton
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"> &</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"> &</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"> &</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"> &</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"> &</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"> &</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"> &</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:
Congrats! That's our first completed dynamic scene!
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:
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!
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:
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!
When you open Blender, you will see some pretty image, made with Belnder, version information, some useful links and recent files
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:
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:
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:
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:
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:
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:
Now let's try something more complex. See the Tools panel on your left?
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 :
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:
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:
Now let's create walls for our "ramp". Create a few loop cuts alongside the ramp and we will start extruding:
Or maybe just moving faces?..
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:
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:
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:
Click the Subdivide item, and the selected edges will be connected right in the middle:
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:
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.
So in the end we need to have two edges on the same line:
Now, switch to the Ortho View , choosing one from the View menu at the bottom of the screen, or hitting the Num 5 key:
Your workspace now should look different:
Using the View menu, you may switch between different views, perpendicular to your model.
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:
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:
Use the Normal one and you will see the arrows at the selected edges changed:
Now movement is done along the edge, just as we need:
Try moving (yes, moving, not extruding) our edges up - they will move along the normal:
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:
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...
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?
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:
Hmmm... It's way too much... Now, hold the Shift key and drag the circle over the neighbour, redundant ones:
Now we can switch back to the Top Ortho View and successfully move our edges:
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:
Now we will scale our model a few times. Staying in the Edit mode , select all the faces with the A key:
And hit the S key and start entering scale factor number. That's right, just press, say, 5 :
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.
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:
Then you pass in some params like texture size, the background color and image name - and you are done!
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:
Now, on the left panel, switch to the Shading/UVs tab and click the Mark Seam button:
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:
Again, no effect you will see now. To see something, switch the window layout at the top menu to UV Editing :
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 :
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:
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 :
And your model will change its look...
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...
Now we are able to paint our model! See, how awesome it is: you have a brush tool activated. Brush has three params:
Radius could be changed by pressing the F key and moving mouse cursor:
Pressure could be changed by pressing Shift + F and doing the same:
And you can just pain like in... Microsoft Paint!
But if you look into the UV/Image editor , you will see... nothing! Again! 'the hell?!
That is just misunderstanging - you were painting on the other image instead of the selected one:
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:
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:
But that's happening not everywhere - only on certain faces/edges:
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:
Try selecting them with Right mouse button and moving them with G :
Yes, now texture looks creepy, but lines are almost straight:
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's file dialogs look differently, but have very intuitive interface:
If you do not see the needed format in Blender - you just need to turn on a corresponding plugin:
After exporting our model to, say, 3DS format, take a look at the directory you have exported your model to:
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 :
Now we have everything we need for our Newtonian sample!
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.
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.
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.
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.
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!
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:
browserName
option)
window
and navigates to the page, defined in the
baseUrl
option
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
.
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:
waitForExist('.title*=iPhone 6 White', settings.timeout)
)
element('.title*=iPhone 6 White').element('..')
)
click('button*=Buy')
)
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.
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.
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:
//
- it tells browser's engine to look for this element everywhere,
independently on its parent
div
; it could be
"any"
selector,
*
, but we precised our search
Let's take a closer look on those - they are really interesting ones:
contains(@class, "row")
; it tells engine to look for an element, whose
class
attribute contains
(or "partially matches" if you wish)
row
string
contains(., "iPhone 6 White")
; it looks for text content inside tag; including its
children
ancestor-or-self::div[@ng-repeat]
, which
looks for
<div>
element with
ng-repeat
attribute in the current element or any of its parents
and
keyword
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.
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 .
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.
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.
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"><</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"><</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"><</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"><=</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"><</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"><>();</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"><</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"><</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"><>();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6"> List</span><span style="color:#7C7F93;--shiki-dark:#949CBB"><</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"><>();</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"><</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<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"><</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"><</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<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"><</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"><=</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"> <</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"><</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"><</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>
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.
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.
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.
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
.
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">& 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.
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:
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">& 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">& 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">& 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.
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!
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!
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.
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) .
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.
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 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 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>
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.
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>
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
.
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.
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 validationThis 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"><></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">"()<>@,;:</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"><></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">"()<>@,;:</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">])*(?:[^()<>@,;:</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">"()<>@,;:</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"><></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">"()<>@,;:</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"><></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"><></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"><</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:#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"><></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"><></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">"()<>@,;:</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"><></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">"()<>@,;:</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"><></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">"()<>@,;:</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"><></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">"()<>@,;:</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"><></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">"()<>@,;:</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"><></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"><></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"><></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">"()<>@,;:</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"><></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">"()<>@,;:</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">])*(?:(?:(?:[^()<>@,;:</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">"()<>@,;:</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">])*(?:[^()<></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"><></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"><></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"><></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"><></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"><></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">])*))*|(?:[^()<>@,;:</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">"()<>@,;:</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">\<</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">\\</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"><></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"><></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"><></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">])*(?:[^()<>@,;:</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">"()<>@,;:</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"><></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"><></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"><></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"><></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"><></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"><></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"><></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"><></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"><></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"><></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"><></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"><></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"><></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">"()<>@,;:</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"><></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"><></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"><></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">"()<>@,;:</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"><></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"><></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"><</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"><></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"><></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"><></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"><></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"><></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"><></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"><></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"><></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"><></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"><></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"><></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"><></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"><></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">"()<>@,;:</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:#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"><></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 =)
At this point we have an application with
That's our "game"? Doubtely... So let's make things move like in real world! Or just like that...
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!
At this point we have an application with
That's our "game"? Doubtely... So let's make things move like in real world! Or just like that...
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!
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"> &</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"> &</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"> &</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"> &</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"> &</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"><</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LuaFunction</span><span style="color:#179299;--shiki-dark:#81C8BE"><</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"><</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">&</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"><</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"> // "<>" 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:
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:
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.
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...)
.
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!
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...)
.
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!
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!
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:
irr::video::IVideoDriver
for rendering operations
irr::scene::ISceneManager
for scene management
So why not to define a
ScriptManager
to handle scripts? Our requirements
for this class (for now) are:
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"><</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"><</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"><</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:
IVideoDriver
and
ISceneManager
to handle 3D objects and the scene
Lua luaState
field to store the current state of our script running
<string, ISceneNode*>
map to allow access to our nodes from scripts
createSphereNode
,
setNodePosition
and
getNodePosition
so we will be able to make some manipulations in our scripts
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:
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<value_type>(index)
and
table.Get<value_type>("key")
methods
to access its values.
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"><</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">&</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>
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>
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"><</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"><</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"><</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:
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
.
We will now advance our script and add some convention to it. These will be our tasks for the rest of this chapter:
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"><</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LuaFunction</span><span style="color:#179299;--shiki-dark:#81C8BE"><</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"><</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"> &</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"><</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LuaFunction</span><span style="color:#179299;--shiki-dark:#81C8BE"><</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"><</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"><</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"><</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LuaFunction</span><span style="color:#179299;--shiki-dark:#81C8BE"><</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"><</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"> &</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"><</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LuaFunction</span><span style="color:#179299;--shiki-dark:#81C8BE"><</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:
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.
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!
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!
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?
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.
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!
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!
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?
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...
Our first application will show you Irrlicht basic features we will use later. They are:
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"> <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">&</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"><</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"><</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"> &</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"><</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"><</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>
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>
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.
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>
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"><</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">&</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.
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> <p>
The next level is how the modules communicate to each other, how they work together.
</p>
<p>
The lower level is the structure of each module - what classes, entities, data structures and similar things will
the module consist of.
</p>
<p>
One of the lowest, yet still very important architecture levels is how files are organized.
</p>
</div>
</code>
From the highest architecture layer point of view, I can advice a very simple architecture:
The main benefits of such an approach are:
We can make the core so flexible that we may re-use it in the future projects.
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!
Remember all the three rules for our architecture. And keeping them in mind, let's get to some coding already!
This tutorial covers the development of a game from a very beginning. This includes:
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:
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.
I expect you to have at least some experience with these three things:
The latter - to make sure, you will not call 3d models “textures” or miss the “script” word’ meaning.
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 .
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.
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.
This article relies on JavaScript, so let's be kind and create an initial project structure for a typical JS project. Just like this:
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.
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)
.
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"> <!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"> <</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"> <</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"> <</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"> <</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"></</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"> <</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"><</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"> <</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"> </</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"> <</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"> </</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"> </</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">html</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>
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.
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"> <</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"> <</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">></</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"> <</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"> <</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"></</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"> </</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.
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"> <</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"> <</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">></</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"> <</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"> <</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"></</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"> </</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:
class
attribute within elements, use
className
instead
<code>
React.render(
<TweetBox />,
document.body
);
</code>
Note: you may not use the
<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
<body>
tag; to make it loaded when all the document is done loading:
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6"> <!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"> <</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"> <</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"> <</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"> <</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"></</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"> <</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"><</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"> <</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"> </</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"> <</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"> <</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"><</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"> </</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"> </</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.
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"> <</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"> <</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">></</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"> <</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"> <</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"></</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"> <</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"></</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"> </</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
<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() {
...
&lt;textarea className="form-control" onChange={ this.handleChange }&gt;
...
}
</code>
Yeah, looks not so pretty as with Angular…
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!
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"> <</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"> <</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"> <</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">></</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"> <</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"> <</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"></</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"> <</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"></</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"> </</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"> <</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"> <</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"> </</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.
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"> <</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">
<div class="well clearfix">
<textarea class="form-control" [(ng-model)]="text"></textarea>
<br/>
<span>{{ maxLength - text.length }}</span>
<button class="btn btn-primary pull-right">Tweet</button>
</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:
[(ng-model)]="modelName"
)
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:
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.
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"><</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"><</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"></</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"><</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"></</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"><</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">></</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"></</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:
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.
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"><</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"> <</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"> </</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"> <</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"></</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"> </</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"> <</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">></</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"> <</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"></</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"> <</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"> </</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!
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!
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
npm
bower init
dependencies
object in your new
bower.json
file
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.
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’
<body>
tag:
<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE"><</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">welcome-component</span><span style="color:#179299;--shiki-dark:#81C8BE">></</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"> <</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"> <</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"> </</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"> <</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"> <</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"></</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"> </</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"> <</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"> </</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"> </</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
<head>
tag of the
index.html
file:
<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE"><</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"> <!-- imports Polymer --></span></span> <span class="line"><span style="color:#179299;--shiki-dark:#81C8BE"><</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"> <!-- 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
<div class="message">
within the
<welcome-component>
tag. And its style will never affect any other elements, even when you create another
<div>
outside the
<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.
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
<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?
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!
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.
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* &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:
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"> <stdio.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <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"> &</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"><</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"> &</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"> &</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:
Argument type is encoded as well. For our example, we see these:
Pi
- that means, literally,
pointer to integer
i
- that stands for
integer
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
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">&</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!
Writing code in assembly language in 2015 seems stupid and meaningless. Yet, it has a few huge benefits:
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.
Writing code in assembly language in 2015 seems stupid and meaningless. Yet, it has a few huge benefits:
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.
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:
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"> <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:
-c
: only compile the code, do not link it (do not search for referenced functions)
-m32
: compile code in a 32-bit mode
-g
: add a debugger information
-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:
-felf32
: compile in a 32-bit mode
-g
: add a debugginng info
-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.
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"> <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:
-S
: generate assembly output
-m32
: generate 32-bit code
-c
: stop after compiling
-masm=intel
: use Intel’ assembly syntax; it is NASM’ syntax and thus more readable then GASM’ one
-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:
sub esp, 8
- this allocates 8 bytes of stack memory for our local variables
[ebp+8]
and
[ebp+12]
are two parts, each 4-byte long, of our argument of type
long long
[ebp-8]
and
[ebp-4]
are two parts of our return value; each 4-byte long; of type
long long
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.
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"> <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 &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!
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:
FLD
,
FLDZ
,
FLD1
, etc.)
FADD
,
FMUL
,
FDIV
,
FSUB
, etc.)
ST0
)
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"> <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:
[0 nan nan nan nan nan nan]
)
v1
to a floating stack
(ST:
[3 0 nan nan nan nan nan]
)
v2
to a floating stack
(ST:
[4 3 0 nan nan nan nan]
)
ST1
and pop stack head
(ST:
[12 0 nan nan nan nan nan]
)
ST1
and pop stack head
(ST:
[12 nan nan nan nan nan nan]
)
i
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.
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"> <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"> &</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"> &</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
c
or
continue
will run program until it hits end or breakpoint
ni
will step one instruction
n
or
next
will step over the next function
(in C)
; for ASM it’s same as
ni
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
quit
Now, using GDB, try to find out what’s wrong with the program I’ve suggested!
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.
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:
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:
plugins/
directory in your build directory
Qt/5.4/Src/qtbase/plugins/platforms/
there
Qt/5.4/gcc_64/plugins/sqldrivers/
there too
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.
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>
Trying some new hardcore - Assembly in Emacs 😁
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"> "<</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"> "</</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"><</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"></</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"><</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"></</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"> '<</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"></</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 !
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 .
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:
Have had some free time and tried sculpting in Blender 😜 With some other nice stuff 😁
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
Just some WIP. Having fun with Blender 😊
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:
sudo dpkg -i package_file.deb && sudo apt-get -f install
sudo dpkg -i --force-depends package_file.deb
Obviously, the second one is better because it is shorter 😁
Playing around with Blender - rendering, modifiers and some basic texturing and materials.
Found these on HabraHabr today. Here are some tricks I found usefull.
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>
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">&</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">&</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">&</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>
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"> <</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"> <</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"> <</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.
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>
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.
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.
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!
The first thing I gonna tell you, is really handy tip.
There are three ways to exit Erlang' shell:
q().
and hit
Return
You'll be happy to know 'bout last two - they are just easier!
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>
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.
So, short summary on what you should have to run distributely in Erlang:
hosts
file
.erlang.cookie
file
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">"< 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>
Much cooler than writing ping-pong programs, huh? =)
This is a 3D model of a robot (called him Robo) which I made in Cinema4D some two and a half years ago.
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><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>
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:
VendorID
and
ProductID
for your device running
lsusb
two times (just find the difference line):
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.
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.
/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>
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>
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?
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! 😉
This tutorial I wrote when was quitting my previous job, almost one year ago. But it's still handy!
<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>
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>
There is a specific utility, called Jungle . It manages your applications' instances at startup.
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"> &</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">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:
setuid apps
and
setgid apps
, uncomment those lines and replace
apps
to whatever your deployment user is.
apps
on the paths (or set the right paths to your user's home) everywhere else.
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/
PENDING
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
.
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.
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 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:
*.so
files) - could be placed anywhere and used in a runtime by a few applications
*.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:
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"> <string.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> <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:
reinterpret_cast
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"><<</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 << " -fPIC "</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># $LDFLAGS << " -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.
Building a Ruby Gem containing native extension is a little different than building usual gems. You here have two options:
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:
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!
Будь готов! В цій главі ми полностью переробим блог! Він не буде працювати (як раньше) аж до кінця домашнього заданія; код буде магічним; придеться пару раз удалять весь код з деяких файлів! Але в сухом остаткє, потом має стати ну дуже прикольно розробляти його дальше.
Будь готов! В цій главі ми полностью переробим блог! Він не буде працювати (як раньше) аж до кінця домашнього заданія; код буде магічним; придеться пару раз удалять весь код з деяких файлів! Але в сухом остаткє, потом має стати ну дуже прикольно розробляти його дальше.
От коли-небудь ти точно міг замітить, шо на сайтах мало ссилок з адрєсами віда
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"><?</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"><?</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&amp;baz=dao
. Йому удобніше, пріятніше читать шось тіпа
/moo/bar?baz=dao
. Тіпа вони будуть запоминать або тіпа вони зможуть записать на бумажці десь це. Не важно особо, нашо це пользоватєлю - главне зробить його щасливим.
Щас ми будем обільно рефлєксірувать. Єсть в PHP така одна чудєсна пєрємєнна, як
$_SERVER
. Це масів. В ньому лежить багато інтересних всяких настройок, але нам поки треба буде тільки одна -
$_SERVER['REQUEST_URI']
. Як не странно, воно слабо зв’язано з сервером. Це - адрєс, який ввів пользоватєль, тільки без домєна. Так шо, якшо у нас сайт називається
<a href="http://google.com/search/">http://google.com/search/</a>
, а пользоватєль введе в адрєсну строку браузєра
<a href="http://google.com/search/moo/foo/bar">http://google.com/search/moo/foo/bar</a>
, то в соотвєтствующому php-файлі, пєрємєнна оця
$_SERVER['REQUEST_URI']
буде мати значення
/moo/foo/bar
.
Але по умолчанію наш сервер перенаправляє пользоватєля на файл
index.php
, при цьому рісує цей
index.php
в адрєс странічки. Нада убрать його відти. Для цього ми візьмем настройки сєрвєра
Apache
(якшо у тебе ВНЕЗАПНО другий сервер - будем шось думать - пиши мені в лічку) і трошки їх поміняєм.
Першим ділом тобі треба включить расширєніє сервера під назвою
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><Directory /var/www/>
AllowOverride all
Options FollowSymlinks
Order allow,deny
Allow from all
</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
. Хай він поки особо нічого крутого не вміє - просто виводить
<h1>I am alive!</h1>
. І це у нас буде екшн
index
:
<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE"><?</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"> '<h1>I am alive!</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"><?</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
можна на каждий файл свій написать.
Якшо ти ще помниш, там де ми визиваєм
require
- виполняється код файла, який ми подключаєм і все що виполнилось вставляється в те місце.
Давай зробим таку інтересну штуку: зробим файлік який-небудь
views/index.html
з яким-небудь HTML і в екшні
PostingsController::index()
просто підключим його:
<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE"><?</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 тільки основної частини страніци. Щитай це вміст тега
<body>
. А контроллєр збирає виведений цей HTML і виводить в свій оддєльний view, в якому і описане все вокруг тега
<body>
- щитай це весь HTML, кромє
<body>
. Для контроллєра цей view називається по-особєнному,
layout
. І от цей лейаут, він може бути один на всі-всі контроллєри, а може бути разний для нєкоторих або і вообщє - свій для каждого кантроллєра.
Так от, давай зробим слєдующім образом: у нас буде папочка
views/layouts
, де будуть лежать разні шаблончики. І ми зробим один шаблончик, який буде аутоматично подтягуватись для каждого контроллєра і назвем його
application.phtml
, як контроллєр “по умолчанію”. Замєть, файл має расширєніє
.phtml
. Це нормально. Це показує шо у нас в файлі є і PHP-код і HTML размєтка. В папочку
views/layouts
давай положим файлік
postings.phtml
куди наб’єм допустім такий HTML:
<code><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<?php echo $body ?>
</body>
</html>
</code>
Тут ми берем якусь пєрємєнну
$body
і виводим її. Простенький файлік, нічого сложного. Але нам нада звідкись достать цей самий
$body
. Для цього ми іспользуєм ще одну інтересну плюшку PHP,
output buffer
. Воно позволяє виполнить якийсь код якби в фоні, а все шо цей код вивів - сохранить в пєрємєнну. Виглядить це так:
<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE"><?</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"><?</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"> "<h1></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$content</span><span style="color:#40A02B;--shiki-dark:#A6D189"></h1>"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>
А от цей код вже виведе
<h1>I am alive!</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"><?</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"><?</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"><?</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"><?</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"><?</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"><?</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"><?</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"> <</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">h1</span><span style="color:#179299;--shiki-dark:#81C8BE">><?</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">?></</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"> <</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"> <?</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"> </</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"><?</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!
Єсть така штука як MVC, Model-View-Controller . Це такий прінцип, по якому програма розділяється на три тіпа дєталєй:
Так от, модель - це такій клас, який работає з рядочками одної таблички і другими табличками, шо прив’язані до нашої. Але тільки якшо та таблічка, з якою работає модель - главна в цій связі. Тоість, якшо у нас є модель Пост і модель Камєнтік , то модель Пост може вліять на Камєнтікі , а от модель Камєнтік вже нічо не може зробити з Постом . Тут таблічка Пост - главна, а таблічка Камєнтік - просто прив’язана до неї.
В общєм, модель - це такий удобний клас, в якому заникані всі запроси до бази даних. Ти визиваєш метод моделі, а получаєш - масив (або не масив, а тільки один його елємєнт) з запісями з бази даних. Або визиваєш другий мєтод і удаляєш/обновляєш/создаєш рядочки в базі.
Єсть така штука як MVC, Model-View-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">&</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">&</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">&</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">&</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">&</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">&</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">&</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">&</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">&</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">-&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">-&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">-&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">-&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">-&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">-&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">&</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">-&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">&</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">&</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">&</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">&</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">&</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">&</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">&</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">&</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">&</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">&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">-&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">&</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">&</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">&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">&</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">&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">-&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-&gt;id";
}
};
</code>
А іспользовать такі моделі тепер - сплошне удовольствіє!
<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE"><?</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"><?</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"> <</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">h2</span><span style="color:#179299;--shiki-dark:#81C8BE">><?</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">?></</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"> <</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"> <?</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"> </</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"> <</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"> <?</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"> </</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"><?</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. Розказувать буду просто, шоб всьо було понятно. Ну шо, паєхалі?
Нехай у нас є який-небудь самий стандартний, простий, перший блог на PHP. Така собі кучка файлів для созданія постов, списка постов, перегляду оддєльного поста, реєстрації, логіна і логаута, камєнтіруванія… Просто купа файлів. В цих файлах у нас і HTML, і PHP код.
Дарагой друг! В цих статтях я розкажу тобі як зробить чоткій блог на чотком язику PHP. Розказувать буду просто, шоб всьо було понятно. Ну шо, паєхалі?
Нехай у нас є який-небудь самий стандартний, простий, перший блог на PHP. Така собі кучка файлів для созданія постов, списка постов, перегляду оддєльного поста, реєстрації, логіна і логаута, камєнтіруванія… Просто купа файлів. В цих файлах у нас і HTML, і PHP код.
Приблизно це виглядить отак:
.
І дуже-дуже нада знать CSS, HTML, ООП в PHP і потом, може, JavaScript і jQuery.
Перед началом роботи краще привести в порядок HTML і CSS - розбити всьо красіво по папочкам (CSS - оддєльно, рісунки - оддєльно, PHP-файли - оддєльно); убрать з HTML всі атрібути
style="..."
, всюди пороздававши класи елементам; пообертать атрібути в кавички (
height="15px"
, а не
height=15px
) і так далєє. Шоб ще прощє було потом читать код.
Першим ділом ми будем умєньшать кількість кода, шо є в нашом блогє. В народі це називається принцип DRY, Don’t Repeat Yourself . Розшифровується воно як пацани не повторяють . В RubyOnRails і других крутих штуках шось подобне реалізовано так, шоб весь HTML-код і PHP-код (ну або там Ruby-код, Python-код, будь-який-язик-программіруванія-код) були оддєльно, ну або хотя би по мінімуму PHP і по максімуму HTML.
Тоість, єсть такі штуки, які називаються View і єсть такі штуки які називаються Controller . Так от, в View - у нас чисто виводиться інформація, форматірується з помощю HTML, а чучуть кода все ще є для всяких циклов, іфов або визовов методов Helper ‘ов (якшо нада хітро вивести шось - ссилку, напрімєр, на пост або на удалєніє поста - шоб самому не писати весь адрєс ссилки - можна воспользоватись допоміжним мєтодом; од того і Helper). А в Controller - весь PHP код, який получає дані з бази даних, методи-Helpers, і вобщє нема HTML кода.
Виглядить це якось отако: якшо у нас було
то має стати
Так шо першим ділом ми будем убирать з нашого 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">&</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">&</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">&</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">&</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-&gt;postings as $posting) { ... }
, а
$_SESSION['user']
- на
$controller-&gt;user
. І це кручє, бо ми можем юзера і в базі тримать, і ще невідомо де. Ну а постінги - так вроді прощє іспользувать.
А тепер давай ще додамо перший метод, який упростить жизнь і покаже мощь архітєктури. Він нам помогатиме формірувать URL до постінга. Це шось тіпа:
<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE"><</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=<?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">>...</</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"><</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">"<?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">>...</</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>
Попробуй зробити всякі другі хелпери - для ссилок на удалєніє постов, на редактіруваніє, і прочі.
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>
I am always being asked at least two questions. Just to verify that I know Ruby basics.
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.
This is simple enough to remember as the answer contains only a few points:
Proc
is an object;
block
is not
Proc
does not check the number of arguments;
lambda
does
lambda
returns from itself;
Proc
returns from the outer (containing the
Proc
call) method
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” .
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>
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.
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:
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:
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!
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:
mysql2
gem
adapter: mysql2
instead of
adapter: mysql
in your
config/database.yml
file
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 😁