<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>jiahao.blog</title><description>Random musings about life and thoughts on software engineering</description><link>https://blog.woojiahao.com</link><language>en-us</language><item><title>The Math Behind Burn Rate Detectors</title><link>https://blog.woojiahao.com/post/burn-rate-detectors-math</link><guid isPermaLink="true">https://blog.woojiahao.com/post/burn-rate-detectors-math</guid><description>&lt;blockquote&gt;
&lt;p&gt;This article is my understanding of the &lt;a href=&quot;https://sre.google/workbook/alerting-on-slos/&quot;&gt;Google SRE Workbook chapter on “Alerting on SLOs”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I highly recommend reading it to get more examples!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;slos-and-error-budgets&quot;&gt;SLOs and error budgets&lt;/h2&gt;
&lt;p&gt;An &lt;strong&gt;SLO&lt;/strong&gt;, or Service Level Objective, is an internal target for a service to meet over a period of time. Common
SLOs are used for service availability and latency SLOs, such as having a &lt;a href=&quot;https://docs.cloud.google.com/architecture/infra-reliability-guide/building-blocks#platform-availability&quot;&gt;5 nines&lt;/a&gt; uptime (99.999% availability).&lt;/p&gt;
&lt;p&gt;When defining an SLO, you also (inherently) define an &lt;strong&gt;error budget&lt;/strong&gt;: the number of errors that can occur within the period of time that stays within the SLO.&lt;/p&gt;
&lt;p&gt;For instance, at an SLO of 99.9% (3 nines), the error budget is 0.1%. So if the service has 1,000,000 requests a month (which we can standardize as 30 days for simplicity),
the error budget is 1,000 errors in the entire month. This means that every day, you can have about &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mfrac&gt;&lt;mjx-frac&gt;&lt;mjx-num&gt;&lt;mjx-nstrut&gt;&lt;/mjx-nstrut&gt;&lt;mjx-mrow size=&quot;s&quot;&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-mrow&gt;&lt;/mjx-num&gt;&lt;mjx-dbox&gt;&lt;mjx-dtable&gt;&lt;mjx-line&gt;&lt;/mjx-line&gt;&lt;mjx-row&gt;&lt;mjx-den&gt;&lt;mjx-dstrut&gt;&lt;/mjx-dstrut&gt;&lt;mjx-mn class=&quot;mjx-n&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c33&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-den&gt;&lt;/mjx-row&gt;&lt;/mjx-dtable&gt;&lt;/mjx-dbox&gt;&lt;/mjx-frac&gt;&lt;/mjx-mfrac&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c33&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c33&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c33&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; errors. Remember this number because we will keep coming back to it as reference!&lt;/p&gt;
&lt;p&gt;If we get 30 errors every day, we would have only gotten 900 errors, and we would have still met our SLO of a 99.9% availability.&lt;/p&gt;
&lt;h2 id=&quot;why-error-rates-dont-scale-well&quot;&gt;Why error rates don’t scale well&lt;/h2&gt;
&lt;p&gt;Typically, most operational health metrics are based on the rate of errors that occur at a period of time, compared to the SLO. We call these &lt;strong&gt;error rate alerts&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;These error rate alerts are very one-dimensional. They primarily focus on detecting regressions of your system at a point in time, and do not adapt well to the total traffic over time.&lt;/p&gt;
&lt;p&gt;For instance, the error rate threshold for the availability of a service with an expected uptime of 99.9% might look like:&lt;/p&gt;
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot; display=&quot;true&quot;&gt;&lt;mjx-math display=&quot;true&quot; style=&quot;margin-left: 0; margin-right: 0;&quot; class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mfrac&gt;&lt;mjx-frac type=&quot;d&quot;&gt;&lt;mjx-num&gt;&lt;mjx-nstrut type=&quot;d&quot;&gt;&lt;/mjx-nstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c66&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c35&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-num&gt;&lt;mjx-dbox&gt;&lt;mjx-dtable&gt;&lt;mjx-line type=&quot;d&quot;&gt;&lt;/mjx-line&gt;&lt;mjx-row&gt;&lt;mjx-den&gt;&lt;mjx-dstrut type=&quot;d&quot;&gt;&lt;/mjx-dstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c66&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c71&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-den&gt;&lt;/mjx-row&gt;&lt;/mjx-dtable&gt;&lt;/mjx-dbox&gt;&lt;/mjx-frac&gt;&lt;/mjx-mfrac&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2264&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c28&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c39&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c39&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c39&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c29&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;
&lt;p&gt;This alert could be configured with a &lt;a href=&quot;https://prometheus.io/docs/prometheus/latest/querying/basics/&quot;&gt;lookback window&lt;/a&gt;
of 15 minutes.&lt;/p&gt;
&lt;p&gt;Then, take the following scenario where the total requests at a point in time is equivalent to the number of 500s:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/burn-rate-detector-math/error-rate-raw.png&quot; alt=&quot;Error rate raw&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this scenario, if we used an error rate alert, it might detect the increase in 500s over the lookback window, and it would compute the error rate at the point in time:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/burn-rate-detector-math/error-rate-window.png&quot; alt=&quot;Error rate point in time&quot;&gt;&lt;/p&gt;
&lt;p&gt;It would calculate something like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Number of 500s: 1&lt;/li&gt;
&lt;li&gt;Number of requests: 1&lt;/li&gt;
&lt;li&gt;Error rate: 100%&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Given that the error rate is 100% and the error rate threshold is 0.1%, the alert would fire. But this is likely a false alarm, as there were no other recurrences of the errors across the rest of the service.&lt;/p&gt;
&lt;p&gt;This is a problem because now the alert has a high &lt;strong&gt;false positive&lt;/strong&gt; rate, creating alert fatigue for responders.&lt;/p&gt;
&lt;h3 id=&quot;why-not-increase-the-lookback-window&quot;&gt;Why not increase the lookback window?&lt;/h3&gt;
&lt;p&gt;A very natural first instinct would be to say, “Why not increase the lookback window so it takes &lt;em&gt;more&lt;/em&gt; errors to trigger the alert?”&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/burn-rate-detector-math/error-rate-longer-window.png&quot; alt=&quot;Error rate point in time longer window&quot;&gt;&lt;/p&gt;
&lt;p&gt;And this is absolutely spot on! In this scenario, suppose that the lookback window is increased to 1 hour instead (4x greater than the previous window):&lt;/p&gt;
&lt;p&gt;Now, the calculations could look like (albeit rather exaggerated but point notwithstanding):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Number of 500s: 1&lt;/li&gt;
&lt;li&gt;Number of requests: 500,000&lt;/li&gt;
&lt;li&gt;Error rate: 0.0002%&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This time, the error rate is much less than the error rate threshold, so an alert doesn’t occur.&lt;/p&gt;
&lt;p&gt;However, suppose that we took a step back and zoomed out, and realized that every hour, we were getting 1-3 errors (averaging 2 an hour).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/burn-rate-detector-math/error-rate-longer-window-zoomed.png&quot; alt=&quot;Error rate point in time longer window zoomed out&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Excuse my awful mouse drawing skills)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Individually, at each lookback window, none of these errors would raise an alert, but if this problem persisted throughout the day, it would have generated an average of 48 alerts in the day, above the error budget of 33.3 errors a day.&lt;/p&gt;
&lt;p&gt;Now, we have a problem of &lt;strong&gt;false negatives&lt;/strong&gt; where a clear issue is going unnoticed because our error rate alert is too loose.&lt;/p&gt;
&lt;h3 id=&quot;what-about-enforcing-that-errors-need-to-be-firing-for-an-extended-duration&quot;&gt;What about enforcing that errors need to be firing for an extended duration?&lt;/h3&gt;
&lt;p&gt;Another great instinct!&lt;/p&gt;
&lt;p&gt;And this is not the same as increasing the lookback window!&lt;/p&gt;
&lt;p&gt;Increasing the lookback window is like saying, “I want to have a wider sampling window so that my error rate is less prone to one-off spikes”, which gives the error rate alert more “breathing room” to ingest more events - error and success - to avoid false positives.&lt;/p&gt;
&lt;p&gt;Increasing the alerting duration is like saying, “I want the problem to last for a sustained duration”. For instance, the service might get bursts of 100% error rates that last for a minute. But a proper issue would be when these 100% error rates last for 10 minutes. In this case, the alert duration would be 10 minutes.&lt;/p&gt;
&lt;p&gt;However, once again, a burst of 100% error rates that last for 5 minutes can then go un-alerted, creating another problem of &lt;strong&gt;false negatives&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So if we can’t really improve the false positive and negatives by using error rate alerts, what can we do?&lt;/p&gt;
&lt;h2 id=&quot;its-a-bird-its-a-plane-its-a-burn-rate-detector&quot;&gt;It’s a bird, it’s a plane, it’s a burn rate detector!&lt;/h2&gt;
&lt;p&gt;Rather than modelling and focusing on the error rate, we should design alerts around &lt;em&gt;how quickly they burn through the error budget&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If our error budget is 33.3 a day, a serious issue would chew through the budget in less time, which could mean that the problem is a slow-burning issue (where it is chewing through the budget consistently throughout half the day) OR a sudden spike (where it immediately chews through the budget).&lt;/p&gt;
&lt;p&gt;To model the rate the error budget is burned, we can use the following:&lt;/p&gt;
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot; display=&quot;true&quot;&gt;&lt;mjx-math display=&quot;true&quot; style=&quot;margin-left: 0; margin-right: 0;&quot; class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mtable style=&quot;min-width: 19.285em;&quot;&gt;&lt;mjx-table&gt;&lt;mjx-itable&gt;&lt;mjx-mtr&gt;&lt;mjx-mtd style=&quot;text-align: right; padding-right: 0; padding-bottom: 0.15em;&quot;&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c61&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;mjx-mtd style=&quot;text-align: left; padding-left: 0; padding-bottom: 0.15em;&quot;&gt;&lt;mjx-mi class=&quot;mjx-n&quot;&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mfrac space=&quot;4&quot;&gt;&lt;mjx-frac type=&quot;d&quot;&gt;&lt;mjx-num&gt;&lt;mjx-nstrut type=&quot;d&quot;&gt;&lt;/mjx-nstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c61&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-num&gt;&lt;mjx-dbox&gt;&lt;mjx-dtable&gt;&lt;mjx-line type=&quot;d&quot;&gt;&lt;/mjx-line&gt;&lt;mjx-row&gt;&lt;mjx-den&gt;&lt;mjx-dstrut type=&quot;d&quot;&gt;&lt;/mjx-dstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c64&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c67&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-den&gt;&lt;/mjx-row&gt;&lt;/mjx-dtable&gt;&lt;/mjx-dbox&gt;&lt;/mjx-frac&gt;&lt;/mjx-mfrac&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;/mjx-mtr&gt;&lt;mjx-mtr&gt;&lt;mjx-mtd style=&quot;text-align: right; padding-right: 0; padding-top: 0.15em; padding-bottom: 0.15em;&quot;&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;mjx-mtd style=&quot;text-align: left; padding-left: 0; padding-top: 0.15em; padding-bottom: 0.15em;&quot;&gt;&lt;mjx-mi class=&quot;mjx-n&quot;&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mfrac space=&quot;4&quot;&gt;&lt;mjx-frac type=&quot;d&quot;&gt;&lt;mjx-num&gt;&lt;mjx-nstrut type=&quot;d&quot;&gt;&lt;/mjx-nstrut&gt;&lt;mjx-mfrac&gt;&lt;mjx-frac&gt;&lt;mjx-num&gt;&lt;mjx-nstrut&gt;&lt;/mjx-nstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c66&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c35&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-num&gt;&lt;mjx-dbox&gt;&lt;mjx-dtable&gt;&lt;mjx-line&gt;&lt;/mjx-line&gt;&lt;mjx-row&gt;&lt;mjx-den&gt;&lt;mjx-dstrut&gt;&lt;/mjx-dstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c66&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c71&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-den&gt;&lt;/mjx-row&gt;&lt;/mjx-dtable&gt;&lt;/mjx-dbox&gt;&lt;/mjx-frac&gt;&lt;/mjx-mfrac&gt;&lt;/mjx-num&gt;&lt;mjx-dbox&gt;&lt;mjx-dtable&gt;&lt;mjx-line type=&quot;d&quot;&gt;&lt;/mjx-line&gt;&lt;mjx-row&gt;&lt;mjx-den&gt;&lt;mjx-dstrut type=&quot;d&quot;&gt;&lt;/mjx-dstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c53&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c4C&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c4F&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-den&gt;&lt;/mjx-row&gt;&lt;/mjx-dtable&gt;&lt;/mjx-dbox&gt;&lt;/mjx-frac&gt;&lt;/mjx-mfrac&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;/mjx-mtr&gt;&lt;mjx-mtr&gt;&lt;mjx-mtd style=&quot;text-align: right; padding-right: 0; padding-top: 0.15em;&quot;&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;mjx-mtd style=&quot;text-align: left; padding-left: 0; padding-top: 0.15em;&quot;&gt;&lt;mjx-mi class=&quot;mjx-n&quot;&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mfrac space=&quot;4&quot;&gt;&lt;mjx-frac type=&quot;d&quot;&gt;&lt;mjx-num&gt;&lt;mjx-nstrut type=&quot;d&quot;&gt;&lt;/mjx-nstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c66&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c35&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-num&gt;&lt;mjx-dbox&gt;&lt;mjx-dtable&gt;&lt;mjx-line type=&quot;d&quot;&gt;&lt;/mjx-line&gt;&lt;mjx-row&gt;&lt;mjx-den&gt;&lt;mjx-dstrut type=&quot;d&quot;&gt;&lt;/mjx-dstrut&gt;&lt;mjx-mrow&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c66&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c71&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-cD7&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c28&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c53&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c4C&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c4F&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c29&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-mrow&gt;&lt;/mjx-den&gt;&lt;/mjx-row&gt;&lt;/mjx-dtable&gt;&lt;/mjx-dbox&gt;&lt;/mjx-frac&gt;&lt;/mjx-mfrac&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;/mjx-mtr&gt;&lt;/mjx-itable&gt;&lt;/mjx-table&gt;&lt;/mjx-mtable&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Burn rate&lt;/th&gt;&lt;th&gt;Error rate at 99.9%&lt;/th&gt;&lt;th&gt;Time to exhaust error budget&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;0.1%&lt;/td&gt;&lt;td&gt;30 days&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;0.2%&lt;/td&gt;&lt;td&gt;15 days&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;1%&lt;/td&gt;&lt;td&gt;3 days&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1000&lt;/td&gt;&lt;td&gt;100%&lt;/td&gt;&lt;td&gt;43 minutes&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;We start shifting our focus from “what are the errors happening at this moment?” to “are the error occurring at this moment going to burn through my error budget more quickly than expected?”&lt;/p&gt;
&lt;p&gt;Then, we define our &lt;strong&gt;consumption threshold&lt;/strong&gt;, which is the threshold that the burn rate exceeds that we deem necessary for alerting. Maybe we want to be alerted when 2% of our error budget is consumed, so the consumption threshold would be 2% of the error budget within the available lookback window.&lt;/p&gt;
&lt;p&gt;With these, we can now define the actual burn rate detector and the alert threshold:&lt;/p&gt;
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot; display=&quot;true&quot;&gt;&lt;mjx-math display=&quot;true&quot; style=&quot;margin-left: 0; margin-right: 0;&quot; class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mtable style=&quot;min-width: 36.263em;&quot;&gt;&lt;mjx-table&gt;&lt;mjx-itable&gt;&lt;mjx-mtr&gt;&lt;mjx-mtd style=&quot;text-align: right; padding-right: 0; padding-bottom: 0.15em;&quot;&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;mjx-mtd style=&quot;text-align: left; padding-left: 0; padding-bottom: 0.15em;&quot;&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c61&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2264&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mtext class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c63&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c70&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c69&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c68&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c68&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6C&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c64&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;/mjx-mtr&gt;&lt;mjx-mtr&gt;&lt;mjx-mtd style=&quot;text-align: right; padding-right: 0; padding-top: 0.15em;&quot;&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;mjx-mtd style=&quot;text-align: left; padding-left: 0; padding-top: 0.15em;&quot;&gt;&lt;mjx-mi class=&quot;mjx-n&quot;&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c21D4&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mfrac space=&quot;4&quot;&gt;&lt;mjx-frac type=&quot;d&quot;&gt;&lt;mjx-num&gt;&lt;mjx-nstrut type=&quot;d&quot;&gt;&lt;/mjx-nstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c66&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c35&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-num&gt;&lt;mjx-dbox&gt;&lt;mjx-dtable&gt;&lt;mjx-line type=&quot;d&quot;&gt;&lt;/mjx-line&gt;&lt;mjx-row&gt;&lt;mjx-den&gt;&lt;mjx-dstrut type=&quot;d&quot;&gt;&lt;/mjx-dstrut&gt;&lt;mjx-mrow&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c66&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c71&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-cD7&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c28&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c53&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c4C&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c4F&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c29&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-mrow&gt;&lt;/mjx-den&gt;&lt;/mjx-row&gt;&lt;/mjx-dtable&gt;&lt;/mjx-dbox&gt;&lt;/mjx-frac&gt;&lt;/mjx-mfrac&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2264&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mfrac space=&quot;4&quot;&gt;&lt;mjx-frac type=&quot;d&quot;&gt;&lt;mjx-num&gt;&lt;mjx-nstrut type=&quot;d&quot;&gt;&lt;/mjx-nstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c53&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c4C&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c4F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c70&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c69&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c64&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c69&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c68&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-num&gt;&lt;mjx-dbox&gt;&lt;mjx-dtable&gt;&lt;mjx-line type=&quot;d&quot;&gt;&lt;/mjx-line&gt;&lt;mjx-row&gt;&lt;mjx-den&gt;&lt;mjx-dstrut type=&quot;d&quot;&gt;&lt;/mjx-dstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c6C&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6B&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c61&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c63&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6B&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c77&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c69&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c64&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c77&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c69&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c68&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-den&gt;&lt;/mjx-row&gt;&lt;/mjx-dtable&gt;&lt;/mjx-dbox&gt;&lt;/mjx-frac&gt;&lt;/mjx-mfrac&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-cD7&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mtext class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c63&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c70&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c69&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c25&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;/mjx-mtr&gt;&lt;/mjx-itable&gt;&lt;/mjx-table&gt;&lt;/mjx-mtable&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;
&lt;p&gt;The &lt;strong&gt;SLO period&lt;/strong&gt; is the entire month in this instance.&lt;/p&gt;
&lt;p&gt;So, if we have a consumption % of 2% for a lookback window of 1 hour, we would have a consumption threshold of:&lt;/p&gt;
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot; display=&quot;true&quot;&gt;&lt;mjx-math display=&quot;true&quot; style=&quot;margin-left: 0; margin-right: 0;&quot; class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mfrac&gt;&lt;mjx-frac type=&quot;d&quot;&gt;&lt;mjx-num&gt;&lt;mjx-nstrut type=&quot;d&quot;&gt;&lt;/mjx-nstrut&gt;&lt;mjx-mrow&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c33&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c64&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c61&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c79&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-cD7&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mtext class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c32&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c34&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c68&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c64&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c61&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c79&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-mrow&gt;&lt;/mjx-num&gt;&lt;mjx-dbox&gt;&lt;mjx-dtable&gt;&lt;mjx-line type=&quot;d&quot;&gt;&lt;/mjx-line&gt;&lt;mjx-row&gt;&lt;mjx-den&gt;&lt;mjx-dstrut type=&quot;d&quot;&gt;&lt;/mjx-dstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c68&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-den&gt;&lt;/mjx-row&gt;&lt;/mjx-dtable&gt;&lt;/mjx-dbox&gt;&lt;/mjx-frac&gt;&lt;/mjx-mfrac&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-cD7&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c32&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mi class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c25&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c34&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c34&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;
&lt;p&gt;So if an issue is burning through our error budget at a rate that is 14.4 (or 1.44% error rate at 99.9% SLO) or greater, we deem it alert-worthy.&lt;/p&gt;
&lt;p&gt;To illustrate this, we can reverse the question, asking ourselves, “How many errors need to occur in the 1 hour lookback window to have a burn rate of 14.4?”&lt;/p&gt;
&lt;p&gt;Let’s constraint this problem by defining that the number of requests is 500,000 and SLO is still 99.9%:&lt;/p&gt;
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot; display=&quot;true&quot;&gt;&lt;mjx-math display=&quot;true&quot; style=&quot;margin-left: 0; margin-right: 0;&quot; class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mtable style=&quot;min-width: 17.028em;&quot;&gt;&lt;mjx-table&gt;&lt;mjx-itable&gt;&lt;mjx-mtr&gt;&lt;mjx-mtd style=&quot;text-align: right; padding-right: 0; padding-bottom: 0.15em;&quot;&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;mjx-mtd style=&quot;text-align: left; padding-left: 0; padding-bottom: 0.15em;&quot;&gt;&lt;mjx-mfrac&gt;&lt;mjx-frac type=&quot;d&quot;&gt;&lt;mjx-num&gt;&lt;mjx-nstrut type=&quot;d&quot;&gt;&lt;/mjx-nstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c66&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c35&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-num&gt;&lt;mjx-dbox&gt;&lt;mjx-dtable&gt;&lt;mjx-line type=&quot;d&quot;&gt;&lt;/mjx-line&gt;&lt;mjx-row&gt;&lt;mjx-den&gt;&lt;mjx-dstrut type=&quot;d&quot;&gt;&lt;/mjx-dstrut&gt;&lt;mjx-mrow&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c66&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c71&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-cD7&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c28&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c53&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c4C&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c4F&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c29&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-mrow&gt;&lt;/mjx-den&gt;&lt;/mjx-row&gt;&lt;/mjx-dtable&gt;&lt;/mjx-dbox&gt;&lt;/mjx-frac&gt;&lt;/mjx-mfrac&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c34&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c34&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;/mjx-mtr&gt;&lt;mjx-mtr&gt;&lt;mjx-mtd style=&quot;text-align: right; padding-right: 0; padding-top: 0.15em; padding-bottom: 0.15em;&quot;&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;mjx-mtd style=&quot;text-align: left; padding-left: 0; padding-top: 0.15em; padding-bottom: 0.15em;&quot;&gt;&lt;mjx-mi class=&quot;mjx-n&quot;&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c21D4&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mfrac space=&quot;4&quot;&gt;&lt;mjx-frac type=&quot;d&quot;&gt;&lt;mjx-num&gt;&lt;mjx-nstrut type=&quot;d&quot;&gt;&lt;/mjx-nstrut&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c66&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c35&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;/mjx-num&gt;&lt;mjx-dbox&gt;&lt;mjx-dtable&gt;&lt;mjx-line type=&quot;d&quot;&gt;&lt;/mjx-line&gt;&lt;mjx-row&gt;&lt;mjx-den&gt;&lt;mjx-dstrut type=&quot;d&quot;&gt;&lt;/mjx-dstrut&gt;&lt;mjx-mrow&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c35&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-cD7&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-mrow&gt;&lt;/mjx-den&gt;&lt;/mjx-row&gt;&lt;/mjx-dtable&gt;&lt;/mjx-dbox&gt;&lt;/mjx-frac&gt;&lt;/mjx-mfrac&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c34&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c34&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;/mjx-mtr&gt;&lt;mjx-mtr&gt;&lt;mjx-mtd style=&quot;text-align: right; padding-right: 0; padding-top: 0.15em;&quot;&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;mjx-mtd style=&quot;text-align: left; padding-left: 0; padding-top: 0.15em;&quot;&gt;&lt;mjx-mi class=&quot;mjx-n&quot;&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c21D4&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mtext class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c66&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c35&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c37&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;2&quot;&gt;&lt;mjx-c class=&quot;mjx-c32&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;/mjx-mtr&gt;&lt;/mjx-itable&gt;&lt;/mjx-table&gt;&lt;/mjx-mtable&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;
&lt;p&gt;This means that we would have to have 7,200 errors to trigger this alert. If this number seems too high, then lowering the consumption % would help to increase the sensitivity of the alert as well. For instance, we can lower the consumption % to 0.5% (so if 0.5% of our error budget is burned, we want to be alerted). This yields a total error count of 1,800 within the lookback window. You could also tighten the SLO so that the error budget decreases, for instance, keeping the consumption % at 2%, but tightening the SLO to 99.999% (5 nines), then the total error count would be 72 instead.&lt;/p&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;I highly recommend taking a pen and paper and trying these computations several times to build up an intuition for how each component influences the others.&lt;/p&gt;&lt;/div&gt;
&lt;h3 id=&quot;tiered-burn-rate-detectors&quot;&gt;Tiered burn rate detectors&lt;/h3&gt;
&lt;p&gt;We can also combine multiple burn rate detectors to create tiers of alerts, where each tier has a different alerting mechanisms (like creating Slack messages, opening tickets, paging, etc) associated with the rate of error consumption. These can be paired with different lookback windows as well:&lt;/p&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Consumption %&lt;/th&gt;&lt;th&gt;Lookback window&lt;/th&gt;&lt;th&gt;Alerting&lt;/th&gt;&lt;th&gt;Burn rate&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;2%&lt;/td&gt;&lt;td&gt;1 hour&lt;/td&gt;&lt;td&gt;Page&lt;/td&gt;&lt;td&gt;14.4&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5%&lt;/td&gt;&lt;td&gt;6 hours&lt;/td&gt;&lt;td&gt;Page&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;10%&lt;/td&gt;&lt;td&gt;3 days&lt;/td&gt;&lt;td&gt;Ticket&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;em&gt;(These are the recommended thresholds from Google)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;These create higher granularity alerts: the first alert detects sharp spikes in errors while the last alert detects slow-burn issues that don’t immediately impact the availability but still burn through the error budget.&lt;/p&gt;
&lt;h3 id=&quot;reducing-false-positives&quot;&gt;Reducing false positives&lt;/h3&gt;
&lt;p&gt;Even with burn rate detectors, false positives can be present: an issue could no longer be ongoing but its tail-end could still exist at the very start of the lookback window, triggering the burn rate detector:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/burn-rate-detector-math/burn-rate-end-of-window.png&quot; alt=&quot;Burn rate end of window&quot;&gt;&lt;/p&gt;
&lt;p&gt;To reduce the rate of false positives, we can introduce a second shorter window that answers the question, “Is this problem ongoing?”&lt;/p&gt;
&lt;p&gt;According to the Google SRE Workbook, this shorter window should be 1/12th the length of the longer window:&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Lookback window&lt;/th&gt;&lt;th&gt;Shorter window&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1 hour&lt;/td&gt;&lt;td&gt;5 minutes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;6 hours&lt;/td&gt;&lt;td&gt;30 minutes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3 days&lt;/td&gt;&lt;td&gt;6 hours&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The consumption threshold is tied to the lookback window, and the shorter window inherits this same window, but its calculation uses the much shorter lookback.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/burn-rate-detector-math/burn-rate-multi-window.png&quot; alt=&quot;Burn rate multi-window&quot;&gt;&lt;/p&gt;
&lt;p&gt;The shorter window will be much spikier than the longer window. We only alert when both the long and short windows exceed the consumption threshold at the same time (see the colored area). In the longer lookback window’s slice (in blue), the short window burn rate does not exceed the consumption threshold, so we do not alert.&lt;/p&gt;
&lt;p&gt;In doing so, we only alert when we confirm that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There is a problem chewing through the SLO (long window)&lt;/li&gt;
&lt;li&gt;The problem is still ongoing (as opposed to having occurred in the past and is currently recovering) (short window)&lt;/li&gt;
&lt;/ol&gt;
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot; display=&quot;true&quot;&gt;&lt;mjx-math display=&quot;true&quot; style=&quot;margin-left: 0; margin-right: 0;&quot; class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mtable style=&quot;min-width: 29.198em;&quot;&gt;&lt;mjx-table&gt;&lt;mjx-itable&gt;&lt;mjx-mtr&gt;&lt;mjx-mtd style=&quot;text-align: right; padding-right: 0; padding-bottom: 0.15em;&quot;&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;mjx-mtd style=&quot;text-align: left; padding-left: 0; padding-bottom: 0.15em;&quot;&gt;&lt;mjx-mtext class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c70&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c61&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c67&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;/mjx-mtr&gt;&lt;mjx-mtr&gt;&lt;mjx-mtd style=&quot;text-align: right; padding-right: 0; padding-top: 0.15em;&quot;&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;mjx-mtd style=&quot;text-align: left; padding-left: 0; padding-top: 0.15em;&quot;&gt;&lt;mjx-mi class=&quot;mjx-n&quot;&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c21D4&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mtext class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c61&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c76&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c61&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c68&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c34&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c34&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2227&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mtext class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c62&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c61&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6F&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c76&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c72&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c35&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c20&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6D&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c69&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c6E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c75&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c74&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c65&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c73&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mtext&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c34&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c2E&quot;&gt;&lt;/mjx-c&gt;&lt;mjx-c class=&quot;mjx-c34&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-tstrut&gt;&lt;/mjx-tstrut&gt;&lt;/mjx-mtd&gt;&lt;/mjx-mtr&gt;&lt;/mjx-itable&gt;&lt;/mjx-table&gt;&lt;/mjx-mtable&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;
&lt;p&gt;Let’s run through a simple exercise to illustrate the point:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Short window burn rate
&lt;ul&gt;
&lt;li&gt;Errors in 5 minutes: 2,000&lt;/li&gt;
&lt;li&gt;Requests in 5 minutes: 10,000&lt;/li&gt;
&lt;li&gt;Burn rate: 200&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Long window burn rate
&lt;ul&gt;
&lt;li&gt;Errors in 1 hour: 8,000&lt;/li&gt;
&lt;li&gt;Requests in 1 hour: 500,000&lt;/li&gt;
&lt;li&gt;Burn rate: 16&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both of these exceed the threshold of 14.4, so an alert fires. Now, when we shift the lookback window further:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Short window burn rate
&lt;ul&gt;
&lt;li&gt;Errors in 5 minutes: 100&lt;/li&gt;
&lt;li&gt;Requests in 5 minutes: 10,000&lt;/li&gt;
&lt;li&gt;Burn rate: 10&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Long window burn rate
&lt;ul&gt;
&lt;li&gt;Errors in 1 hour: 7,500&lt;/li&gt;
&lt;li&gt;Requests in 1 hour: 500,000&lt;/li&gt;
&lt;li&gt;Burn rate: 15&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this scenario, even though the long window still contains the remnants of the errors, the short window does not capture it, so the alert does not fire.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope that this article was able to motivate the math behind burn rate detectors and how it solves problems that error rate alerts do not.&lt;/p&gt;
&lt;p&gt;I have become a big proponent of favoring burn rate detectors over error rate alerts to develop golden signals for system health that error rate alerts simply could not provide.&lt;/p&gt;
&lt;h3 id=&quot;further-reading&quot;&gt;Further reading&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.datadoghq.com/blog/burn-rate-is-better-error-rate/&quot;&gt;Burn rate is a better error rate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sre.google/workbook/alerting-on-slos/&quot;&gt;Alerting on SLOs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;style&gt;
mjx-container[jax=&quot;CHTML&quot;] {
  line-height: 0;
}

mjx-container [space=&quot;1&quot;] {
  margin-left: .111em;
}

mjx-container [space=&quot;2&quot;] {
  margin-left: .167em;
}

mjx-container [space=&quot;3&quot;] {
  margin-left: .222em;
}

mjx-container [space=&quot;4&quot;] {
  margin-left: .278em;
}

mjx-container [space=&quot;5&quot;] {
  margin-left: .333em;
}

mjx-container [rspace=&quot;1&quot;] {
  margin-right: .111em;
}

mjx-container [rspace=&quot;2&quot;] {
  margin-right: .167em;
}

mjx-container [rspace=&quot;3&quot;] {
  margin-right: .222em;
}

mjx-container [rspace=&quot;4&quot;] {
  margin-right: .278em;
}

mjx-container [rspace=&quot;5&quot;] {
  margin-right: .333em;
}

mjx-container [size=&quot;s&quot;] {
  font-size: 70.7%;
}

mjx-container [size=&quot;ss&quot;] {
  font-size: 50%;
}

mjx-container [size=&quot;Tn&quot;] {
  font-size: 60%;
}

mjx-container [size=&quot;sm&quot;] {
  font-size: 85%;
}

mjx-container [size=&quot;lg&quot;] {
  font-size: 120%;
}

mjx-container [size=&quot;Lg&quot;] {
  font-size: 144%;
}

mjx-container [size=&quot;LG&quot;] {
  font-size: 173%;
}

mjx-container [size=&quot;hg&quot;] {
  font-size: 207%;
}

mjx-container [size=&quot;HG&quot;] {
  font-size: 249%;
}

mjx-container [width=&quot;full&quot;] {
  width: 100%;
}

mjx-box {
  display: inline-block;
}

mjx-block {
  display: block;
}

mjx-itable {
  display: inline-table;
}

mjx-row {
  display: table-row;
}

mjx-row &gt; * {
  display: table-cell;
}

mjx-mtext {
  display: inline-block;
  text-align: left;
}

mjx-mstyle {
  display: inline-block;
}

mjx-merror {
  display: inline-block;
  color: red;
  background-color: yellow;
}

mjx-mphantom {
  visibility: hidden;
}

_::-webkit-full-page-media, _:future, :root mjx-container {
  will-change: opacity;
}

mjx-math {
  display: inline-block;
  text-align: left;
  line-height: 0;
  text-indent: 0;
  font-style: normal;
  font-weight: normal;
  font-size: 100%;
  font-size-adjust: none;
  letter-spacing: normal;
  border-collapse: collapse;
  word-wrap: normal;
  word-spacing: normal;
  white-space: nowrap;
  direction: ltr;
  padding: 1px 0;
}

mjx-container[jax=&quot;CHTML&quot;][display=&quot;true&quot;] {
  display: block;
  text-align: center;
  margin: 1em 0;
}

mjx-container[jax=&quot;CHTML&quot;][display=&quot;true&quot;][width=&quot;full&quot;] {
  display: flex;
}

mjx-container[jax=&quot;CHTML&quot;][display=&quot;true&quot;] mjx-math {
  padding: 0;
}

mjx-container[jax=&quot;CHTML&quot;][justify=&quot;left&quot;] {
  text-align: left;
}

mjx-container[jax=&quot;CHTML&quot;][justify=&quot;right&quot;] {
  text-align: right;
}

mjx-mfrac {
  display: inline-block;
  text-align: left;
}

mjx-frac {
  display: inline-block;
  vertical-align: 0.17em;
  padding: 0 .22em;
}

mjx-frac[type=&quot;d&quot;] {
  vertical-align: .04em;
}

mjx-frac[delims] {
  padding: 0 .1em;
}

mjx-frac[atop] {
  padding: 0 .12em;
}

mjx-frac[atop][delims] {
  padding: 0;
}

mjx-dtable {
  display: inline-table;
  width: 100%;
}

mjx-dtable &gt; * {
  font-size: 2000%;
}

mjx-dbox {
  display: block;
  font-size: 5%;
}

mjx-num {
  display: block;
  text-align: center;
}

mjx-den {
  display: block;
  text-align: center;
}

mjx-mfrac[bevelled] &gt; mjx-num {
  display: inline-block;
}

mjx-mfrac[bevelled] &gt; mjx-den {
  display: inline-block;
}

mjx-den[align=&quot;right&quot;], mjx-num[align=&quot;right&quot;] {
  text-align: right;
}

mjx-den[align=&quot;left&quot;], mjx-num[align=&quot;left&quot;] {
  text-align: left;
}

mjx-nstrut {
  display: inline-block;
  height: .054em;
  width: 0;
  vertical-align: -.054em;
}

mjx-nstrut[type=&quot;d&quot;] {
  height: .217em;
  vertical-align: -.217em;
}

mjx-dstrut {
  display: inline-block;
  height: .505em;
  width: 0;
}

mjx-dstrut[type=&quot;d&quot;] {
  height: .726em;
}

mjx-line {
  display: block;
  box-sizing: border-box;
  min-height: 1px;
  height: .06em;
  border-top: .06em solid;
  margin: .06em -.1em;
  overflow: hidden;
}

mjx-line[type=&quot;d&quot;] {
  margin: .18em -.1em;
}

mjx-mrow {
  display: inline-block;
  text-align: left;
}

mjx-mn {
  display: inline-block;
  text-align: left;
}

mjx-c {
  display: inline-block;
}

mjx-utext {
  display: inline-block;
  padding: .75em 0 .2em 0;
}

mjx-mo {
  display: inline-block;
  text-align: left;
}

mjx-stretchy-h {
  display: inline-table;
  width: 100%;
}

mjx-stretchy-h &gt; * {
  display: table-cell;
  width: 0;
}

mjx-stretchy-h &gt; * &gt; mjx-c {
  display: inline-block;
  transform: scalex(1.0000001);
}

mjx-stretchy-h &gt; * &gt; mjx-c::before {
  display: inline-block;
  width: initial;
}

mjx-stretchy-h &gt; mjx-ext {
  /* IE */ overflow: hidden;
  /* others */ overflow: clip visible;
  width: 100%;
}

mjx-stretchy-h &gt; mjx-ext &gt; mjx-c::before {
  transform: scalex(500);
}

mjx-stretchy-h &gt; mjx-ext &gt; mjx-c {
  width: 0;
}

mjx-stretchy-h &gt; mjx-beg &gt; mjx-c {
  margin-right: -.1em;
}

mjx-stretchy-h &gt; mjx-end &gt; mjx-c {
  margin-left: -.1em;
}

mjx-stretchy-v {
  display: inline-block;
}

mjx-stretchy-v &gt; * {
  display: block;
}

mjx-stretchy-v &gt; mjx-beg {
  height: 0;
}

mjx-stretchy-v &gt; mjx-end &gt; mjx-c {
  display: block;
}

mjx-stretchy-v &gt; * &gt; mjx-c {
  transform: scaley(1.0000001);
  transform-origin: left center;
  overflow: hidden;
}

mjx-stretchy-v &gt; mjx-ext {
  display: block;
  height: 100%;
  box-sizing: border-box;
  border: 0px solid transparent;
  /* IE */ overflow: hidden;
  /* others */ overflow: visible clip;
}

mjx-stretchy-v &gt; mjx-ext &gt; mjx-c::before {
  width: initial;
  box-sizing: border-box;
}

mjx-stretchy-v &gt; mjx-ext &gt; mjx-c {
  transform: scaleY(500) translateY(.075em);
  overflow: visible;
}

mjx-mark {
  display: inline-block;
  height: 0px;
}

mjx-mtable {
  display: inline-block;
  text-align: center;
  vertical-align: .25em;
  position: relative;
  box-sizing: border-box;
  border-spacing: 0;
  border-collapse: collapse;
}

mjx-mstyle[size=&quot;s&quot;] mjx-mtable {
  vertical-align: .354em;
}

mjx-labels {
  position: absolute;
  left: 0;
  top: 0;
}

mjx-table {
  display: inline-block;
  vertical-align: -.5ex;
  box-sizing: border-box;
}

mjx-table &gt; mjx-itable {
  vertical-align: middle;
  text-align: left;
  box-sizing: border-box;
}

mjx-labels &gt; mjx-itable {
  position: absolute;
  top: 0;
}

mjx-mtable[justify=&quot;left&quot;] {
  text-align: left;
}

mjx-mtable[justify=&quot;right&quot;] {
  text-align: right;
}

mjx-mtable[justify=&quot;left&quot;][side=&quot;left&quot;] {
  padding-right: 0 ! important;
}

mjx-mtable[justify=&quot;left&quot;][side=&quot;right&quot;] {
  padding-left: 0 ! important;
}

mjx-mtable[justify=&quot;right&quot;][side=&quot;left&quot;] {
  padding-right: 0 ! important;
}

mjx-mtable[justify=&quot;right&quot;][side=&quot;right&quot;] {
  padding-left: 0 ! important;
}

mjx-mtable[align] {
  vertical-align: baseline;
}

mjx-mtable[align=&quot;top&quot;] &gt; mjx-table {
  vertical-align: top;
}

mjx-mtable[align=&quot;bottom&quot;] &gt; mjx-table {
  vertical-align: bottom;
}

mjx-mtable[side=&quot;right&quot;] mjx-labels {
  min-width: 100%;
}

mjx-mtr {
  display: table-row;
  text-align: left;
}

mjx-mtr[rowalign=&quot;top&quot;] &gt; mjx-mtd {
  vertical-align: top;
}

mjx-mtr[rowalign=&quot;center&quot;] &gt; mjx-mtd {
  vertical-align: middle;
}

mjx-mtr[rowalign=&quot;bottom&quot;] &gt; mjx-mtd {
  vertical-align: bottom;
}

mjx-mtr[rowalign=&quot;baseline&quot;] &gt; mjx-mtd {
  vertical-align: baseline;
}

mjx-mtr[rowalign=&quot;axis&quot;] &gt; mjx-mtd {
  vertical-align: .25em;
}

mjx-mtd {
  display: table-cell;
  text-align: center;
  padding: .215em .4em;
}

mjx-mtd:first-child {
  padding-left: 0;
}

mjx-mtd:last-child {
  padding-right: 0;
}

mjx-mtable &gt; * &gt; mjx-itable &gt; *:first-child &gt; mjx-mtd {
  padding-top: 0;
}

mjx-mtable &gt; * &gt; mjx-itable &gt; *:last-child &gt; mjx-mtd {
  padding-bottom: 0;
}

mjx-tstrut {
  display: inline-block;
  height: 1em;
  vertical-align: -.25em;
}

mjx-labels[align=&quot;left&quot;] &gt; mjx-mtr &gt; mjx-mtd {
  text-align: left;
}

mjx-labels[align=&quot;right&quot;] &gt; mjx-mtr &gt; mjx-mtd {
  text-align: right;
}

mjx-mtd[extra] {
  padding: 0;
}

mjx-mtd[rowalign=&quot;top&quot;] {
  vertical-align: top;
}

mjx-mtd[rowalign=&quot;center&quot;] {
  vertical-align: middle;
}

mjx-mtd[rowalign=&quot;bottom&quot;] {
  vertical-align: bottom;
}

mjx-mtd[rowalign=&quot;baseline&quot;] {
  vertical-align: baseline;
}

mjx-mtd[rowalign=&quot;axis&quot;] {
  vertical-align: .25em;
}

mjx-mi {
  display: inline-block;
  text-align: left;
}

mjx-c::before {
  display: block;
  width: 0;
}

.MJX-TEX {
  font-family: MJXZERO, MJXTEX;
}

.TEX-B {
  font-family: MJXZERO, MJXTEX-B;
}

.TEX-I {
  font-family: MJXZERO, MJXTEX-I;
}

.TEX-MI {
  font-family: MJXZERO, MJXTEX-MI;
}

.TEX-BI {
  font-family: MJXZERO, MJXTEX-BI;
}

.TEX-S1 {
  font-family: MJXZERO, MJXTEX-S1;
}

.TEX-S2 {
  font-family: MJXZERO, MJXTEX-S2;
}

.TEX-S3 {
  font-family: MJXZERO, MJXTEX-S3;
}

.TEX-S4 {
  font-family: MJXZERO, MJXTEX-S4;
}

.TEX-A {
  font-family: MJXZERO, MJXTEX-A;
}

.TEX-C {
  font-family: MJXZERO, MJXTEX-C;
}

.TEX-CB {
  font-family: MJXZERO, MJXTEX-CB;
}

.TEX-FR {
  font-family: MJXZERO, MJXTEX-FR;
}

.TEX-FRB {
  font-family: MJXZERO, MJXTEX-FRB;
}

.TEX-SS {
  font-family: MJXZERO, MJXTEX-SS;
}

.TEX-SSB {
  font-family: MJXZERO, MJXTEX-SSB;
}

.TEX-SSI {
  font-family: MJXZERO, MJXTEX-SSI;
}

.TEX-SC {
  font-family: MJXZERO, MJXTEX-SC;
}

.TEX-T {
  font-family: MJXZERO, MJXTEX-T;
}

.TEX-V {
  font-family: MJXZERO, MJXTEX-V;
}

.TEX-VB {
  font-family: MJXZERO, MJXTEX-VB;
}

mjx-stretchy-v mjx-c, mjx-stretchy-h mjx-c {
  font-family: MJXZERO, MJXTEX-S1, MJXTEX-S4, MJXTEX, MJXTEX-A ! important;
}

@font-face /* 0 */ {
  font-family: MJXZERO;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Zero.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 1 */ {
  font-family: MJXTEX;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Main-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 2 */ {
  font-family: MJXTEX-B;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Main-Bold.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 3 */ {
  font-family: MJXTEX-I;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Math-Italic.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 4 */ {
  font-family: MJXTEX-MI;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Main-Italic.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 5 */ {
  font-family: MJXTEX-BI;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Math-BoldItalic.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 6 */ {
  font-family: MJXTEX-S1;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Size1-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 7 */ {
  font-family: MJXTEX-S2;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Size2-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 8 */ {
  font-family: MJXTEX-S3;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Size3-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 9 */ {
  font-family: MJXTEX-S4;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Size4-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 10 */ {
  font-family: MJXTEX-A;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_AMS-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 11 */ {
  font-family: MJXTEX-C;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 12 */ {
  font-family: MJXTEX-CB;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Bold.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 13 */ {
  font-family: MJXTEX-FR;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Fraktur-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 14 */ {
  font-family: MJXTEX-FRB;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Fraktur-Bold.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 15 */ {
  font-family: MJXTEX-SS;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_SansSerif-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 16 */ {
  font-family: MJXTEX-SSB;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_SansSerif-Bold.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 17 */ {
  font-family: MJXTEX-SSI;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_SansSerif-Italic.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 18 */ {
  font-family: MJXTEX-SC;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Script-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 19 */ {
  font-family: MJXTEX-T;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Typewriter-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 20 */ {
  font-family: MJXTEX-V;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Vector-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 21 */ {
  font-family: MJXTEX-VB;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Vector-Bold.woff&quot;) format(&quot;woff&quot;);
}

mjx-c.mjx-c31::before {
  padding: 0.666em 0.5em 0 0;
  content: &quot;1&quot;;
}

mjx-c.mjx-c2C::before {
  padding: 0.121em 0.278em 0.194em 0;
  content: &quot;,&quot;;
}

mjx-c.mjx-c30::before {
  padding: 0.666em 0.5em 0.022em 0;
  content: &quot;0&quot;;
}

mjx-c.mjx-c33::before {
  padding: 0.665em 0.5em 0.022em 0;
  content: &quot;3&quot;;
}

mjx-c.mjx-c3D::before {
  padding: 0.583em 0.778em 0.082em 0;
  content: &quot;=&quot;;
}

mjx-c.mjx-c2E::before {
  padding: 0.12em 0.278em 0 0;
  content: &quot;.&quot;;
}

mjx-c.mjx-c6E::before {
  padding: 0.442em 0.556em 0 0;
  content: &quot;n&quot;;
}

mjx-c.mjx-c75::before {
  padding: 0.442em 0.556em 0.011em 0;
  content: &quot;u&quot;;
}

mjx-c.mjx-c6D::before {
  padding: 0.442em 0.833em 0 0;
  content: &quot;m&quot;;
}

mjx-c.mjx-c62::before {
  padding: 0.694em 0.556em 0.011em 0;
  content: &quot;b&quot;;
}

mjx-c.mjx-c65::before {
  padding: 0.448em 0.444em 0.011em 0;
  content: &quot;e&quot;;
}

mjx-c.mjx-c72::before {
  padding: 0.442em 0.392em 0 0;
  content: &quot;r&quot;;
}

mjx-c.mjx-c20::before {
  padding: 0 0.25em 0 0;
  content: &quot; &quot;;
}

mjx-c.mjx-c6F::before {
  padding: 0.448em 0.5em 0.01em 0;
  content: &quot;o&quot;;
}

mjx-c.mjx-c66::before {
  padding: 0.705em 0.372em 0 0;
  content: &quot;f&quot;;
}

mjx-c.mjx-c35::before {
  padding: 0.666em 0.5em 0.022em 0;
  content: &quot;5&quot;;
}

mjx-c.mjx-c73::before {
  padding: 0.448em 0.394em 0.011em 0;
  content: &quot;s&quot;;
}

mjx-c.mjx-c71::before {
  padding: 0.442em 0.528em 0.194em 0;
  content: &quot;q&quot;;
}

mjx-c.mjx-c74::before {
  padding: 0.615em 0.389em 0.01em 0;
  content: &quot;t&quot;;
}

mjx-c.mjx-c2264::before {
  padding: 0.636em 0.778em 0.138em 0;
  content: &quot;\2264&quot;;
}

mjx-c.mjx-c28::before {
  padding: 0.75em 0.389em 0.25em 0;
  content: &quot;(&quot;;
}

mjx-c.mjx-c2212::before {
  padding: 0.583em 0.778em 0.082em 0;
  content: &quot;\2212&quot;;
}

mjx-c.mjx-c39::before {
  padding: 0.666em 0.5em 0.022em 0;
  content: &quot;9&quot;;
}

mjx-c.mjx-c29::before {
  padding: 0.75em 0.389em 0.25em 0;
  content: &quot;)&quot;;
}

mjx-c.mjx-c61::before {
  padding: 0.448em 0.5em 0.011em 0;
  content: &quot;a&quot;;
}

mjx-c.mjx-c64::before {
  padding: 0.694em 0.556em 0.011em 0;
  content: &quot;d&quot;;
}

mjx-c.mjx-c67::before {
  padding: 0.453em 0.5em 0.206em 0;
  content: &quot;g&quot;;
}

mjx-c.mjx-c2D::before {
  padding: 0.252em 0.333em 0 0;
  content: &quot;-&quot;;
}

mjx-c.mjx-c53::before {
  padding: 0.705em 0.556em 0.022em 0;
  content: &quot;S&quot;;
}

mjx-c.mjx-c4C::before {
  padding: 0.683em 0.625em 0 0;
  content: &quot;L&quot;;
}

mjx-c.mjx-c4F::before {
  padding: 0.705em 0.778em 0.022em 0;
  content: &quot;O&quot;;
}

mjx-c.mjx-cD7::before {
  padding: 0.491em 0.778em 0 0;
  content: &quot;\D7&quot;;
}

mjx-c.mjx-c63::before {
  padding: 0.448em 0.444em 0.011em 0;
  content: &quot;c&quot;;
}

mjx-c.mjx-c70::before {
  padding: 0.442em 0.556em 0.194em 0;
  content: &quot;p&quot;;
}

mjx-c.mjx-c69::before {
  padding: 0.669em 0.278em 0 0;
  content: &quot;i&quot;;
}

mjx-c.mjx-c68::before {
  padding: 0.694em 0.556em 0 0;
  content: &quot;h&quot;;
}

mjx-c.mjx-c6C::before {
  padding: 0.694em 0.278em 0 0;
  content: &quot;l&quot;;
}

mjx-c.mjx-c21D4::before {
  padding: 0.526em 1em 0.025em 0;
  content: &quot;\21D4&quot;;
}

mjx-c.mjx-c6B::before {
  padding: 0.694em 0.528em 0 0;
  content: &quot;k&quot;;
}

mjx-c.mjx-c77::before {
  padding: 0.431em 0.722em 0.011em 0;
  content: &quot;w&quot;;
}

mjx-c.mjx-c25::before {
  padding: 0.75em 0.833em 0.056em 0;
  content: &quot;%&quot;;
}

mjx-c.mjx-c79::before {
  padding: 0.431em 0.528em 0.204em 0;
  content: &quot;y&quot;;
}

mjx-c.mjx-c32::before {
  padding: 0.666em 0.5em 0 0;
  content: &quot;2&quot;;
}

mjx-c.mjx-c34::before {
  padding: 0.677em 0.5em 0 0;
  content: &quot;4&quot;;
}

mjx-c.mjx-c2F::before {
  padding: 0.75em 0.5em 0.25em 0;
  content: &quot;/&quot;;
}

mjx-c.mjx-c2265::before {
  padding: 0.636em 0.778em 0.138em 0;
  content: &quot;\2265&quot;;
}

mjx-c.mjx-c37::before {
  padding: 0.676em 0.5em 0.022em 0;
  content: &quot;7&quot;;
}

mjx-c.mjx-c76::before {
  padding: 0.431em 0.528em 0.011em 0;
  content: &quot;v&quot;;
}

mjx-c.mjx-c2227::before {
  padding: 0.598em 0.667em 0.022em 0;
  content: &quot;\2227&quot;;
}
&lt;/style&gt;</description><pubDate>Fri, 04 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Unified Data Modelling with Elixir</title><link>https://blog.woojiahao.com/post/unified-data-modelling-with-elixir</link><guid isPermaLink="true">https://blog.woojiahao.com/post/unified-data-modelling-with-elixir</guid><description>&lt;p&gt;The &lt;a href=&quot;https://datamall.lta.gov.sg/content/datamall/en/dynamic-data.html&quot;&gt;LTA public bus schedule API&lt;/a&gt; is an amazing public resource for anyone looking to integrate Singapore’s public transport data into their applications. However, a core limitation with the API is its relatively aggressive pagination (500 rows per response). It is understandable why it has to exist given that the API is free to use and has virtually no rate limits, but it was not feasible for the project I am working on (I’ll publish a short about it soon!) as I wanted to fetch all of the data at once.&lt;/p&gt;
&lt;p&gt;To fetch all of the data at once while avoiding spamming the API, I built an intermediate API that would bulk-load the data from the endpoints I was interested in (bus routes, bus stops, and bus arrivals) and cache the results for a day to avoid repeated API requests.&lt;/p&gt;
&lt;p&gt;Of course, being an Elixir fanboy, I wanted to write this intermediate API in Phoenix. While writing this API, I encountered a fun application of metaprogramming: unified data modelling.&lt;/p&gt;
&lt;h2 id=&quot;traditional-api-response-data-modelling&quot;&gt;Traditional API response data modelling&lt;/h2&gt;
&lt;p&gt;Traditionally, if you were building a service that ingests an API, you would introduce a &lt;a href=&quot;https://en.wikipedia.org/wiki/Data_transfer_object&quot;&gt;data transfer object (DTO)&lt;/a&gt; to parse the API response, along with a DTO for your own API responses:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/unified-data-modelling-with-elixir/traditional-api-modelling.png&quot; alt=&quot;Traditional API Modelling&quot;&gt;&lt;/p&gt;
&lt;p&gt;The intermediate API service will receive the LTA API response, transform it into an &lt;strong&gt;API DTO&lt;/strong&gt; to match the fields, and then convert that DTO to a different format that can be returned to the user (called the &lt;strong&gt;internal DTO&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;Common conversion steps include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Removing fields&lt;/li&gt;
&lt;li&gt;Renaming fields (like changing the case from PascalCase to snake_case)&lt;/li&gt;
&lt;li&gt;Parsing data&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Suppose that the API responds with the following format:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// GET /api/people?$skip=0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;John&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;occupation&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Student&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;homeAddress&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;18 Baker Street&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Mary&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;occupation&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Teacher&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;homeAddress&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A DTO could look like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; API&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Person&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  defstruct&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:occupation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:homeAddress&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And have the serialization library convert the API responses to the DTO.&lt;/p&gt;
&lt;p&gt;Then, the output DTO could look like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Person&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  defstruct&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:occupation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:home_address&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @derive {&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Jason&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Encoder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, []}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @spec &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;from_api&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;API&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Person&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; from_api&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(api) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    %&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      name:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; api.name,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      occupation:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; api.occupation,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      home_address:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; api.homeAddress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is discounting providing type safety to both models by declaring &lt;code&gt;@type t&lt;/code&gt;, providing custom parsing for fields, and the cost to add new fields or modify fields as both DTOs would have to change, and many more features.&lt;/p&gt;
&lt;h1 id=&quot;introducing-unified-data-modelling&quot;&gt;Introducing… unified data modelling&lt;/h1&gt;
&lt;p&gt;Rather than creating two separate data models, Elixir allows us to create a single model that handles both parsing and output using some clever metaprogramming constructs.&lt;/p&gt;
&lt;p&gt;We would also like to ideally address the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Automatically generating consistent &lt;code&gt;@type t&lt;/code&gt; definitions&lt;/li&gt;
&lt;li&gt;Support custom parsing for fields like date times and special formats&lt;/li&gt;
&lt;li&gt;Make it easy to add/delete/modify/hide fields&lt;/li&gt;
&lt;li&gt;Generate OpenAPI specifications&lt;/li&gt;
&lt;li&gt;Generate &lt;code&gt;defstruct&lt;/code&gt; for all fields&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;However, for the sake of simplicity, let’s keep it extremely simple and design a unified data model that only takes in string fields.&lt;/p&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;The full unified data model for BusWhere can be found in &lt;a href=&quot;https://github.com/woojiahao/bus-where-api/blob/main/lib/bus_where_api/models/model_base.ex&quot;&gt;this GitHub repository&lt;/a&gt;, where it covers more complex features like custom parsing and enum handling.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;Working backwards, let’s come up with what a unified data model might look like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Person&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  use&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ModelBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  field &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  field &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:occupation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;occupation&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  field &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:home_address&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;homeAddress&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We want to declare fields with the &lt;code&gt;field&lt;/code&gt; macro, passing in the internal DTO’s field name, the field type, and the API DTO’s field name. These should then generate&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;defstruct [:name, :occupation, :home_address]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@type t&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;def from_body()&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So the final &lt;code&gt;Model.Person&lt;/code&gt; looks like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Person&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  defstruct&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:occupation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:home_address&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @derive {&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Jason&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Encoder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, []}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @type t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    name:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    occupation:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    home_address:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; from_body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(body) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    %&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      name:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; body[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      occupation:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; body[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;occupation&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      home_address:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; body[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;homeAddress&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And handle any other work that is necessary to then allow the intermediate API to return the model directly as a JSON response (i.e. serialization).&lt;/p&gt;
&lt;h2 id=&quot;macros-recap&quot;&gt;Macros recap&lt;/h2&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;If you wish to have a deep dive into metaprogramming in Elixir, we have a series on it you &lt;a href=&quot;https://blog.woojiahao.com/post/an-introduction-to-metaprogramming-in-elixir&quot;&gt;can read here&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;We will cover most concepts in this article again, but one core idea to learn before diving in is how macros are treated in Elixir, particularly how the compiler handles them.&lt;/p&gt;
&lt;p&gt;Elixir is a compiled language, so the compiler first parses files, converts the syntax into an &lt;a href=&quot;https://en.wikipedia.org/wiki/Abstract_syntax_tree&quot;&gt;Abstract Syntax Tree (AST)&lt;/a&gt; and then compiles the AST into BEAM VM bytecode which is then converted to machine code.&lt;/p&gt;
&lt;p&gt;While parsing files, the compiler will encounter macros, which is then executed, expanding the macro in place of the macro call, using the body of a &lt;code&gt;quote&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmacro&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  quote&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    IO&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;puts&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hi&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Bar&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  foo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# ===&gt; results in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Bar&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  IO&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;puts&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hi&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;quote&lt;/code&gt; converts its body into an AST representation so all values are preserved as-is till compilation. To evaluate values before they are converted to an AST, use &lt;code&gt;unquote&lt;/code&gt; within a &lt;code&gt;quote&lt;/code&gt; :&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmacro&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(number) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  quote&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; number &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# this translates to `x + number` which is not valid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(number) &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# this translates to `x + 11` for e.g.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;More precisely, &lt;code&gt;unquote&lt;/code&gt; inserts the AST directly, so numbers are valid ASTs, but when dealing with more complex data structures, make sure that they are an AST first, before using &lt;code&gt;unquote&lt;/code&gt; on them.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;After the compiler expands all the macros and evaluates any behavior, the final AST is then compiled into the module.&lt;/p&gt;
&lt;h2 id=&quot;step-0-creating-the-model-base&quot;&gt;Step 0: Creating the model base&lt;/h2&gt;
&lt;p&gt;We first need to declare a &lt;code&gt;ModelBase&lt;/code&gt; that all unified data models will &lt;code&gt;use&lt;/code&gt; :&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ModelBase&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @callback &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;from_body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  defmacro&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; __using__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_opts&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    quote&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      @derive {&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Jason&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Encoder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, []}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ModelBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      Module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register_attribute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:fields&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;accumulate:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      @before_compile &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ModelBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To use this &lt;code&gt;ModelBase&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Person&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  use&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ModelBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;use&lt;/code&gt; macro in Elixir triggers the &lt;code&gt;__using__&lt;/code&gt; macro, resulting in the following module upon compilation:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# after macro expansion&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Person&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @derive {&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Jason&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Encoder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, []}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ModelBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  Module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register_attribute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:fields&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;accumulate:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @before_compile &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ModelBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It behaves &lt;em&gt;very&lt;/em&gt; similarly (but not exactly) to inheritance in OOP, allowing you to embed common behavior across modules.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@derive {Jason.Encoder, []}&lt;/code&gt; — support serialization&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import Model.ModelBase&lt;/code&gt; — use functions and macros in &lt;code&gt;Model.ModelBase&lt;/code&gt; without using &lt;code&gt;Model.ModelBase.xxx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Module.register_attribute&lt;/code&gt; — registers the &lt;code&gt;@field&lt;/code&gt; module attribute that can accumulate values every time you call it&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@before_compile Model.ModelBase&lt;/code&gt; — calls the &lt;code&gt;before_compile&lt;/code&gt; macro before the &lt;code&gt;Model.Person&lt;/code&gt; module is actually compiled from AST into BEAM VM code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This sets up the core of how the unified data model will work, we will now need to add macros to &lt;code&gt;Model.ModelBase&lt;/code&gt; to make it a reality.&lt;/p&gt;
&lt;h2 id=&quot;step-1-declaring-fields&quot;&gt;Step 1: Declaring fields&lt;/h2&gt;
&lt;p&gt;We want to declare fields using a single macro — providing both the internal and API DTO field names, along with the data type. We use the &lt;code&gt;@fields&lt;/code&gt; accumulating module attribute that we declared using &lt;code&gt;__using__&lt;/code&gt; :&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Model.ModelBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@spec &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;field&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;atom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;atom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Macro&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmacro&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; field&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(internal_name, field_type, api_name) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  quote&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @fields {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(internal_name),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(field_type),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(api_name)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we use the &lt;code&gt;field&lt;/code&gt; macro inside &lt;code&gt;Model.Person&lt;/code&gt;, the macros will get expanded to:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Model.ModelPerson&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# field :name, :string, &quot;name&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@fields {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  :name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  :string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;name&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# field :occupation, :string, &quot;occupation&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@fields {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  :occupation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  :string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;occupation&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# field :home_address, :string, &quot;homeAddress&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@fields {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  :home_address&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  :string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;homeAddress&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And because we set the field to &lt;code&gt;accumulate: true&lt;/code&gt;, the &lt;code&gt;@fields&lt;/code&gt; module attribute actually looks like this once all of the &lt;code&gt;field&lt;/code&gt; macros are expanded:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@fields [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    :name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    :string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;name&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    :occupation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    :string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;occupation&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    :home_address&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    :string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;homeAddress&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;step-2-declaring-the-struct&quot;&gt;Step 2: Declaring the struct&lt;/h2&gt;
&lt;p&gt;We want to now use the values of &lt;code&gt;@fields&lt;/code&gt; to provide a &lt;code&gt;defstruct&lt;/code&gt; call in &lt;code&gt;Model.Person&lt;/code&gt; , like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Person&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # values from __using__&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  defstruct&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:occupation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:home_address&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, as we are expanding the macro calls, we do not have access to the full value of &lt;code&gt;@fields&lt;/code&gt; because we don’t know when &lt;code&gt;field&lt;/code&gt; calls end.&lt;/p&gt;
&lt;p&gt;To combat this, we use the &lt;code&gt;__before_compile__&lt;/code&gt; macro, which slots itself after the macro expansion but right before the compilation of the module, so it has access to the latest AST of the module after all other macros are expanded, allowing you to make one final update to the AST of the module with the knowledge of things like the final value of module attributes like &lt;code&gt;@fields&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;So the compiler steps look like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Parse raw module code — AST 1&lt;/li&gt;
&lt;li&gt;Identify and expand all macro calls — AST 2&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;__before_compile__&lt;/code&gt; to modify AST 2 — AST 3&lt;/li&gt;
&lt;li&gt;Compile AST 3 into final module&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is what we need &lt;code&gt;__before_compile__&lt;/code&gt; to do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Load the value of &lt;code&gt;@fields&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Extract the &lt;code&gt;name&lt;/code&gt; component of each field&lt;/li&gt;
&lt;li&gt;Use these values in &lt;code&gt;defstruct&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Model.ModelBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmacro&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; __before_compile__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(env) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  fields &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get_attribute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(env.module, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:fields&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  field_names &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Enum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    fields, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    fn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {field, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_key&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_opts&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      {field, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  quote&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    defstruct&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(field_names)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Module.get_attribute&lt;/code&gt; — retrieves the &lt;code&gt;@fields&lt;/code&gt; value&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://Enum.map&quot;&gt;&lt;code&gt;Enum.map&lt;/code&gt;&lt;/a&gt; — converts the &lt;code&gt;@fields&lt;/code&gt; list of tuples to an array of atoms&lt;/li&gt;
&lt;li&gt;&lt;code&gt;defstruct unquote(field_names)&lt;/code&gt; — unquotes the array of atoms from the previous step into the macro&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This produces the intended compiled &lt;code&gt;Model.Person&lt;/code&gt; module as seen above.&lt;/p&gt;
&lt;h2 id=&quot;step-3-converting-api-to-internal-fields&quot;&gt;Step 3: Converting API to internal fields&lt;/h2&gt;
&lt;p&gt;With the &lt;code&gt;@fields&lt;/code&gt; loaded, we can then parse each of the values from the API response into the internal fields. We can centralize this behavior in the function &lt;code&gt;from_body&lt;/code&gt; (previously &lt;code&gt;from_api&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Model.Person&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@spec &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;from_body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; from_body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(api) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  %&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    name:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; api.name,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    occupation:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; api.occupation,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    home_address:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; api.homeAddress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Given that we may want to parse the API fields like converting strings to integers or booleans, handling enums, parsing special formats, we can build a general parsing layer by declaring &lt;code&gt;parse&lt;/code&gt; functions that are responsible for taking the type of each field and applying the appropriate parsing rules to each:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Model.ModelBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, api_value, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; api_value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, api_value, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  when&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; is_integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(api_value) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; is_float&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(api_value), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; api_value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, api_value, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  when&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; is_binary&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(api_value), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;to_integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(api_value)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To setup the &lt;code&gt;from_body&lt;/code&gt; definition in every model, we add to the &lt;code&gt;__before_compile__&lt;/code&gt; macro:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Model.ModelBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmacro&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; __before_compile__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(env) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # @fields preprocessing...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  escaped_fields &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Macro&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;escape&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(fields)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  quote&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # defstruct...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; from_body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(body) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; is_map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(body) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      Enum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reduce&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(escaped_fields), &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        fn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {field, type, key, opts}, acc &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          raw_value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(body, key)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(type, raw_value, opts)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;          Map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(acc, field, value)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; from_body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # parse functions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;Note that we need to escape &lt;code&gt;fields&lt;/code&gt; and then &lt;code&gt;unquote&lt;/code&gt; it because &lt;code&gt;unquote&lt;/code&gt; inserts the AST in-place, so we need to insert the AST of the &lt;code&gt;fields&lt;/code&gt; array, not the &lt;code&gt;fields&lt;/code&gt; array directly (which is invalid).&lt;/p&gt;&lt;p&gt;More in the &lt;a href=&quot;https://elixir.hexdocs.pm/Kernel.SpecialForms.html#unquote/1&quot;&gt;Elixir documentation&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;For every &lt;code&gt;field&lt;/code&gt;, we:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Extract the raw value from the &lt;code&gt;body&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Parse the raw value using the &lt;code&gt;parse&lt;/code&gt; functions&lt;/li&gt;
&lt;li&gt;Accumulate them into a &lt;code&gt;%__MODULE__{}&lt;/code&gt;, which is &lt;code&gt;Model.Person&lt;/code&gt; in this case&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, we have the &lt;code&gt;from_body&lt;/code&gt; function. At this stage, if we call &lt;code&gt;Model.Person.from_body(api_response_body)&lt;/code&gt;, we will get a struct of &lt;code&gt;Model.Person&lt;/code&gt;, parsing the API response body into the internal model.&lt;/p&gt;
&lt;h2 id=&quot;step-4-declaring-type-t&quot;&gt;Step 4: Declaring &lt;code&gt;@type t&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The final piece we want is to automatically generate the &lt;code&gt;@type t&lt;/code&gt; definition so that we can guarantee type safety and type usage through &lt;code&gt;Model.Person.t()&lt;/code&gt;. Normally, you would need to declare &lt;code&gt;@type t&lt;/code&gt; manually:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Model.Person&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@type t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  name:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  occupation:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  home_address:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But with macros, we can dynamically generate them based on the &lt;code&gt;field&lt;/code&gt; values:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Model.ModelBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmacro&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; __before_compile__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(env) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # @fields preprocessing...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  field_types &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Enum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    fields,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    fn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {field, type, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      {field, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;type_spec&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(type)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  struct_type &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [], &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:%{}&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [], field_types}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      ]}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  quote&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # defstruct...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # from_body&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @type t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(struct_type)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # parse functions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; type_spec&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; quote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; type_spec&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; quote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similar to &lt;code&gt;parse&lt;/code&gt;, we declare helper functions &lt;code&gt;type_spec&lt;/code&gt; to convert the declared type values to the appropriate type signatures, like &lt;code&gt;String.t()&lt;/code&gt; and &lt;code&gt;integer()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We also need to explicitly build the &lt;code&gt;@type t&lt;/code&gt; struct’s AST and &lt;code&gt;unquote&lt;/code&gt; it. The AST results in the exact &lt;code&gt;@type t&lt;/code&gt; definition you see above. This needs to all be done before &lt;code&gt;quote&lt;/code&gt; since we want to evaluate these values before the macro is expanded.&lt;/p&gt;
&lt;h2 id=&quot;and&quot;&gt;And…&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://i.makeagif.com/media/1-18-2021/QtYj4G.gif&quot; alt=&quot;Peter griffin Tada&quot;&gt;&lt;/p&gt;
&lt;p&gt;We now have a fully unified data model &lt;code&gt;Model.Person&lt;/code&gt; that works as both the API and internal DTO, with all of the type generation and parsing handled automatically. It scales with any number of fields and adding new support for field types or parsing is as simple as supporting new &lt;code&gt;parse&lt;/code&gt; and &lt;code&gt;type_spec&lt;/code&gt; helper functions. You can also use the &lt;code&gt;Model.ModelBase&lt;/code&gt; in any number of data models, plugging in just &lt;code&gt;use Model.ModelBase&lt;/code&gt;  and using all the &lt;code&gt;field&lt;/code&gt; macros.&lt;/p&gt;
&lt;p&gt;If you want to see how enum values from the API is handled, or how union types can be generated, or how custom parsing for fields is implemented, you can refer to the &lt;code&gt;ModelBase&lt;/code&gt; &lt;a href=&quot;https://github.com/woojiahao/bus-where-api/blob/main/lib/bus_where_api/models/model_base.ex&quot;&gt;written for BusWhere&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is the final &lt;code&gt;Model.ModelBase&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ModelBase&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @callback &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;from_body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  defmacro&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; __using__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_opts&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    quote&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      @derive {&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Jason&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Encoder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, []}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ModelBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      Module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register_attribute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:fields&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;accumulate:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      @before_compile &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ModelBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @spec &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;field&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;atom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;atom&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Macro&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  defmacro&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; field&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(internal_name, field_type, api_name) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    quote&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      @fields {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(internal_name),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(field_type),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(api_name)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  defmacro&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; __before_compile__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(env) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    fields &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get_attribute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(env.module, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:fields&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    field_names &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Enum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      fields, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      fn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {field, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_key&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_opts&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        field&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    escaped_fields &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Macro&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;escape&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(fields)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    field_types &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Enum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      fields,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      fn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {field, type, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {field, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;type_spec&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(type)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    struct_type &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [], &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:%{}&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [], field_types}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        ]}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    quote&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      defstruct&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(field_names)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; from_body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(body) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; is_map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(body) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        Enum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reduce&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;          unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(escaped_fields), &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;          fn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {field, type, key, opts}, acc &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            raw_value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(body, key)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(type, raw_value, opts)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            Map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(acc, field, value)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;          end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; from_body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      @type t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(struct_type)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, api_value, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; api_value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, api_value, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    when&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; is_integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(api_value) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; is_float&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(api_value), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; api_value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, api_value, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    when&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; is_binary&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(api_value), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;to_integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(api_value)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; type_spec&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; quote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; type_spec&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; quote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description><pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate></item><item><title>Running Docker in GitHub Action steps</title><link>https://blog.woojiahao.com/post/docker-in-github-action-step</link><guid isPermaLink="true">https://blog.woojiahao.com/post/docker-in-github-action-step</guid><description>&lt;p&gt;Working on the packaging and publishing pipeline for the &lt;a href=&quot;https://git-mastery.github.io&quot;&gt;Git-Mastery&lt;/a&gt; &lt;a href=&quot;https://github.com/git-mastery/app&quot;&gt;app&lt;/a&gt; revealed many interesting problems in software packaging, particularly for Linux distributions like Debian and Arch Linux.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;/post/packaging-and-publishing-on-debian&quot;&gt;my last post&lt;/a&gt;, I shared about the packaging and publishing process for Debian, and how it is pretty non-trivial to get going, especially if you want to support multiple architectures and automate the pipeline using &lt;a href=&quot;https://github.com/features/actions&quot;&gt;GitHub Actions&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;a-silver-lining&quot;&gt;A silver lining?&lt;/h2&gt;
&lt;p&gt;One benefit of packaging and publishing for Debian through GitHub Actions is that there is a &lt;a href=&quot;https://github.com/actions/runner-images&quot;&gt;GitHub-hosted runner&lt;/a&gt; for &lt;a href=&quot;https://ubuntu.com/&quot;&gt;Ubuntu&lt;/a&gt;, a Debian-based distribution. This means we can easily translate the steps we would take regularly to package and publish a &lt;code&gt;.deb&lt;/code&gt; manually to the steps a GitHub Action job would use.&lt;/p&gt;
&lt;p&gt;But packaging for &lt;a href=&quot;https://archlinux.org/&quot;&gt;Arch Linux&lt;/a&gt; does not share the same benefit. There is no GitHub-hosted runner for Arch Linux, so when performing certain actions during the packaging process (like using &lt;code&gt;makepkg&lt;/code&gt;), we do not have access to these commands in the Ubuntu hosted runner, and this is a major limitation in the packaging process.&lt;/p&gt;
&lt;h2 id=&quot;so-what-do-we-do&quot;&gt;So, what do we do?&lt;/h2&gt;
&lt;p&gt;Luckily, we can &lt;a href=&quot;https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/run-jobs-in-a-container&quot;&gt;run jobs in a container&lt;/a&gt;, where you can:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Define a &lt;code&gt;Dockerfile&lt;/code&gt; to set up the container&lt;/li&gt;
&lt;li&gt;Run all your steps within this container&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In doing so, we can define a job that runs an Arch Linux base image as a Docker container&lt;/p&gt;
&lt;p&gt;That’s it right? Simple as that.&lt;/p&gt;
&lt;p&gt;Well, not exactly…&lt;/p&gt;
&lt;h2 id=&quot;wait-whats-wrong&quot;&gt;Wait, what’s wrong?&lt;/h2&gt;
&lt;p&gt;Depending on the container we select, we might need to perform additional set up to prepare the container to include the typical dependencies of the GitHub-hosted runners.&lt;/p&gt;
&lt;p&gt;Common tools like &lt;code&gt;python&lt;/code&gt; and &lt;code&gt;git&lt;/code&gt; &lt;em&gt;may&lt;/em&gt; not exist, and it is up to us - the designers of these pipelines - to set up these dependencies and ensure that the container is fit to use.&lt;/p&gt;
&lt;p&gt;It might seem simple enough to fix, but some actions that you rely on may also make assumptions about their dependencies, which creates a pretty painful experience all the way down.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/docker-in-github-action-step/meme.png&quot; alt=&quot;Hehe haha&quot;&gt;&lt;/p&gt;
&lt;p&gt;Instead, it may be easier (given your specific context), to use Docker containers in certain steps, so you get the full benefit of the GitHub-hosted runners while giving you the &lt;strong&gt;option&lt;/strong&gt; to access a different underlying operating system for a step or two.&lt;/p&gt;
&lt;h2 id=&quot;what-the-title-promised&quot;&gt;What the title promised&lt;/h2&gt;
&lt;p&gt;To achieve this, an implicit requirement exists: the Docker container and the runner must be able to share files with each other.&lt;/p&gt;
&lt;p&gt;This is very easily achievable by &lt;a href=&quot;https://docs.docker.com/engine/storage/volumes/&quot;&gt;mounting a volume&lt;/a&gt; in Docker to a folder in the runner.&lt;/p&gt;
&lt;p&gt;By doing this, we can now communicate between the Docker container and the runner.&lt;/p&gt;
&lt;p&gt;The rest is relatively straight forward:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --rm&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  -v&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $PWD&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;:/pkg&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  archlinux:base-devel&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  bash&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    pacman -Sy --noconfirm sudo git base-devel &amp;#x26;&amp;#x26; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    useradd -m builder &amp;#x26;&amp;#x26; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    echo &apos;builder ALL=(ALL) NOPASSWD: ALL&apos; &gt;&gt; /etc/sudoers &amp;#x26;&amp;#x26; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    chown -R builder:builder /pkg &amp;#x26;&amp;#x26; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    su builder -c &apos;cd /pkg &amp;#x26;&amp;#x26; makepkg --printsrcinfo &gt; .SRCINFO&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; chown&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -R&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That seems like a whole lot of nonsense, but in essence, we are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;--rm&lt;/code&gt;: telling Docker to remove the container when it exits&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v $PWD:/pkg&lt;/code&gt;: mounting the current working directory of the runner with a directory called &lt;code&gt;/pkg&lt;/code&gt; in the Docker container&lt;/li&gt;
&lt;li&gt;&lt;code&gt;archlinux:base-devl&lt;/code&gt;: specifying the image that Docker will use&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bash -c&lt;/code&gt;: runs the following string as a bash command&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You don’t need to concern yourself with the specific bash commands running, these are all specific to publishing on Arch Linux (I will be making a post on this soon!).&lt;/p&gt;
&lt;p&gt;The final step involves fixing the permissions of the files generated by the Docker container so that the runner is able to properly access and interact with them.&lt;/p&gt;
&lt;p&gt;When the files are generated from within the Docker container, even if they are stored in a mounted volume, they will still “belong” to the user within the container. This user will differ from the user in the runner, and this can be problematic for permissions on the runner.&lt;/p&gt;
&lt;p&gt;So &lt;code&gt;sudo chown -R $(id -u):$(id -g) .&lt;/code&gt; sets the permissions of all files (recursively) within the current directory (aka the mounted volume) back to the runner’s user’s details.&lt;/p&gt;
&lt;p&gt;You can extend this by treating the mounted volume as a communication protocol between the Docker container and the runner: using it to store values in shared files that can be read by the runner and used to set environment variables afterwards:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --rm&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  -v&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $PWD&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;:/pkg&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  archlinux:base-devel&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  bash&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    echo &apos;FOO=hi&apos; &gt;&gt; /pkg/test.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; chown&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -R&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; test.txt&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$GITHUB_ENV&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description><pubDate>Tue, 10 Feb 2026 00:00:00 GMT</pubDate></item><item><title>Packaging and Publishing on Debian</title><link>https://blog.woojiahao.com/post/packaging-and-publishing-on-debian</link><guid isPermaLink="true">https://blog.woojiahao.com/post/packaging-and-publishing-on-debian</guid><description>&lt;p&gt;As part of developing &lt;a href=&quot;https://git-mastery.github.io&quot;&gt;Git-Mastery&lt;/a&gt;, I had to publish the &lt;a href=&quot;https://git-mastery.github.io/app&quot;&gt;app&lt;/a&gt; across as many operating systems as possible for students to download it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.debian.org/&quot;&gt;Debian&lt;/a&gt; was a target operating system as students may be using Debian/&lt;a href=&quot;https://ubuntu.com/&quot;&gt;Ubuntu&lt;/a&gt;/some &lt;a href=&quot;https://distrowatch.com/search.php?basedon=Debian&quot;&gt;Debian-based Linux distro&lt;/a&gt; as their daily driver or they may be using &lt;a href=&quot;https://ubuntu.com/desktop/wsl&quot;&gt;Ubuntu for Windows Subsystem for Linux (WSL)&lt;/a&gt; on Windows.&lt;/p&gt;
&lt;p&gt;Surprisingly, the process of packaging the app for Debian was way more involved than I had originally anticipated, taking over a day of experimentation to integrate with &lt;a href=&quot;https://github.com/features/actions&quot;&gt;GitHub Actions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While there are several nice guides covering individual steps of this process, I found myself having to piece them together as I was working on this that, and I had eventually &lt;a href=&quot;https://woojiahao.notion.site/linux-packaging-226f881eda0580d68bc8dc6f8e1d5d0d?source=copy_link&quot;&gt;compiled a set of pretty comprehensive notes&lt;/a&gt; on my findings.&lt;/p&gt;
&lt;p&gt;I wanted to use this opportunity to consolidate my process and hopefully remove the awkwardness on figuring out how to package and publish applications on Debian!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I am not claiming to be subject matter expert, and I may have some inefficient steps below!&lt;/p&gt;
&lt;p&gt;If you spot any, feel free to &lt;a href=&quot;mailto:woojiahao1234@gmail.com&quot;&gt;drop me an email&lt;/a&gt; and I will improve it!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;what-will-be-covered&quot;&gt;What will be covered?&lt;/h2&gt;
&lt;p&gt;This guide hopes to cover the following core topics:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Packaging your application on Debian (creating a &lt;code&gt;.deb&lt;/code&gt; file)&lt;/li&gt;
&lt;li&gt;Creating a Debian repository using &lt;code&gt;reprepo&lt;/code&gt; and GitHub Pages&lt;/li&gt;
&lt;li&gt;Publishing multi-architecture packages&lt;/li&gt;
&lt;li&gt;Automating packaging and publishing using GitHub Actions&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before packaging your application, you first need to create an ELF binary of your program (which I will refer to as a “binary” or “executable” from here on out). I will use the Git-Mastery app binary for reference.&lt;/p&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;If you wish to follow along, you can get &lt;code&gt;v7.1.2&lt;/code&gt; of the &lt;a href=&quot;https://github.com/git-mastery/app/releases/download/v7.1.2/gitmastery-7.1.2-linux-arm64&quot;&gt;binary on ARM64 here&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;The Git-Mastery app uses &lt;a href=&quot;https://pyinstaller.org/en/stable/&quot;&gt;PyInstaller&lt;/a&gt; to bundle the CLI into a single executable, and it uses the &lt;a href=&quot;https://github.com/actions/runner-images&quot;&gt;Ubuntu GitHub Actions image&lt;/a&gt; to generate this executable across architectures.&lt;/p&gt;
&lt;p&gt;If you are not using GitHub Actions, the next easiest option is to use a &lt;a href=&quot;https://www.vmware.com/topics/virtual-machine&quot;&gt;Virtual Machine&lt;/a&gt; (VM) to build it. You can also use the VM to run through the individual steps of packaging, so I highly recommend setting one up now. I have included my set-up for a Debian ARM64 VM on MacOS Apple Silicon in &lt;a href=&quot;#appendix-setting-up-a-debian-vm-on-macos-apple-silicon&quot;&gt;the appendix below&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, you will need to ensure that you have the &lt;code&gt;devscripts&lt;/code&gt; and &lt;code&gt;debhelper-compat&lt;/code&gt; packages installed in your environment.&lt;/p&gt;
&lt;p&gt;In Debian, you can install it using &lt;code&gt;apt&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; apt-get&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; devscripts&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; build-essential&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; debhelper-compat&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;core-concepts&quot;&gt;Core concepts&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://wiki.debian.org/Packaging/Intro&quot;&gt;official introduction to packaging on Debian&lt;/a&gt; provides some high-level details about the packaging process that I will (shamelessly) copy over to explain some fundamental concepts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Upstream tarball:&lt;/strong&gt; a &lt;a href=&quot;https://en.wikipedia.org/wiki/Tarball_(computing)&quot;&gt;tarball&lt;/a&gt; (&lt;code&gt;.tar.gz&lt;/code&gt; or &lt;code&gt;.tgz&lt;/code&gt;) that contains the software that has been written (i.e. it contains the executable)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source package:&lt;/strong&gt; built from the upstream source; “contains the upstream source distribution, configuration for the package build system, list of runtime dependencies and conflicting packages, …”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Binary package:&lt;/strong&gt; built from the source package which is then distributed and installed; contains (among other things) the executables and resources required for the executable to run&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In our context, the upstream tarball simply contains the executable that you intend to publish and the binary package is the resulting &lt;code&gt;.deb&lt;/code&gt; file that is consumed by users, so these should be relatively straightforward to understand.&lt;/p&gt;
&lt;p&gt;Instead, the focus of this guide is the construction of the source package, allowing tools like &lt;code&gt;dpkg-buildpackage&lt;/code&gt; (&lt;a href=&quot;https://man7.org/linux/man-pages/man1/dpkg-buildpackage.1.html&quot;&gt;man&lt;/a&gt;) to build and create the binary package.&lt;/p&gt;
&lt;p&gt;The simplest source package consists of:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The upstream tarball&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;debian/&lt;/code&gt; directory containing the changes made to the upstream source and all files required for the creation of the binary package&lt;/li&gt;
&lt;li&gt;A description file (&lt;code&gt;.dsc&lt;/code&gt;) which contains metadata about the above files&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This guide will focus on these three as the primary packaging workflow.&lt;/p&gt;
&lt;h2 id=&quot;creating-the-upstream-tarball&quot;&gt;&lt;strong&gt;Creating the upstream tarball&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Given that you are packaging your own application, you will first create the upstream tarball.&lt;/p&gt;
&lt;p&gt;Start by creating a folder for your executable. I chose to name mine using the following convention &lt;code&gt;&amp;#x3C;name&gt;-&amp;#x3C;version&gt;-&amp;#x3C;architecture&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gitmastery-7.1.2-arm64/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, copy the executable into this folder.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gitmastery-7.1.2-linux-arm64&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gitmastery-7.1.2-arm64/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, generate the tarball following naming convention: &lt;code&gt;&amp;#x3C;name&gt;_&amp;#x3C;version&gt;.orig.tar.gz&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tar&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -czf&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gitmastery_7.1.2.orig.tar.gz&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gitmastery-7.1.2-arm64/gitmastery-7.1.2-linux-arm64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;creating-the-debian-directory&quot;&gt;&lt;strong&gt;Creating the &lt;code&gt;debian/&lt;/code&gt; directory&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Navigate into the folder containing your executable.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gitmastery-7.1.2-arm64/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, create a sub-folder named &lt;code&gt;debian&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; debian&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is where all the configuration about packaging your application will be held.&lt;/p&gt;
&lt;p&gt;There are several files you will need within &lt;code&gt;debian/&lt;/code&gt; to tell the packaging tool how to create your package:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;debian/changelog&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://wiki.debian.org/DebianChangelog&quot;&gt;Debian Changelog&lt;/a&gt; is where you (as the maintainer) log the changes to a package. If you are packaging the application using GitHub Actions, you could lift it from the latest commit message on the repository.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; show&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; v7.1.2&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --no-patch&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --pretty=format:%s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Otherwise, you can specify it directly when generating the file using &lt;code&gt;dch&lt;/code&gt; (&lt;a href=&quot;https://manpages.debian.org/jessie/devscripts/dch.1.en.html&quot;&gt;man&lt;/a&gt;).&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;dch&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --create&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; 7.1.2-1&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; low&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --package&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gitmastery&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Changed things&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--create&lt;/code&gt; : generates a new &lt;code&gt;debian/changelog&lt;/code&gt; file (note that it expects the &lt;code&gt;debian/&lt;/code&gt; sub-folder so run this command outside of the &lt;code&gt;debian/&lt;/code&gt; sub-folder)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v 7.1.2-1&lt;/code&gt;: specifying the version of the application listed in the changelog; &lt;code&gt;-1&lt;/code&gt; indicates the release number of the package&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-u low&lt;/code&gt;: indicates the &lt;a href=&quot;https://lists.debian.org/debian-mentors/2008/02/msg00567.html&quot;&gt;urgency&lt;/a&gt; of the changelog entry; tied to the &lt;a href=&quot;https://www.debian.org/devel/testing&quot;&gt;Debian “testing” distribution&lt;/a&gt;; &lt;code&gt;low&lt;/code&gt; implies that the package may transition to “testing” in 10 days&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--package&lt;/code&gt;: name of the package&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;debian/control&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;control&lt;/code&gt; file describes the source and binary package, providing information about the name, maintainers, and build dependencies.&lt;/p&gt;
&lt;p&gt;You can generate this file using the following template:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Source: gitmastery&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Maintainer: Jiahao, Woo &amp;#x3C;woojiahao1234@gmail.com&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Section: misc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Priority: optional&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Standards-Version: 4.7.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Build-Depends: debhelper-compat (= 13)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Package: gitmastery&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Architecture: arm64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Depends: ${shlibs:Depends}, ${misc:Depends}, libc6 (&gt;= 2.35), python3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Description: execute Git-Mastery&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gitmastery is a Git learning tool built by the National University of Singapore School of Computing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is broken up into two parts: source and binary.&lt;/p&gt;
&lt;p&gt;In the source section:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Source&lt;/code&gt;: source package name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Maintainer&lt;/code&gt;: name and email of the person responsible for the package; follows the &lt;code&gt;$NAME &amp;#x3C;$EMAIL&gt;&lt;/code&gt; format&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Priority&lt;/code&gt;: priority of the package to indicate whether the package is important to the standard functioning system; one of &lt;code&gt;required&lt;/code&gt;, &lt;code&gt;important&lt;/code&gt;, &lt;code&gt;standard&lt;/code&gt;, &lt;code&gt;optional&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Build-Depends&lt;/code&gt;: list of packages that need to be installed to build the package (note this does not imply that the package can run with these dependencies, just that it can be built)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the binary section:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Package&lt;/code&gt;: name of the binary package which might differ from the source package name (in our case it doesn’t)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Architecture&lt;/code&gt;: specifies the computer architecture where the binary package is expected to work, including &lt;code&gt;arm64&lt;/code&gt; and &lt;code&gt;amd64&lt;/code&gt; (the two primary architectures I chose to focus on)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Depends&lt;/code&gt;: list of packages that must be installed for the program in the binary package to work; &lt;code&gt;${shlibs:Depends}&lt;/code&gt; are the packages that contain built shared libraries and executables and &lt;code&gt;${misc:Depends}&lt;/code&gt; contain the packages like &lt;code&gt;debhelper&lt;/code&gt; (here we also list &lt;code&gt;libc&lt;/code&gt; and &lt;code&gt;python3&lt;/code&gt; as extra dependencies)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Description&lt;/code&gt;: full description of the binary package; first line is a summary and the rest of the lines are a longer description&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;debian/copyright&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The name is pretty self-explanatory - this contains the copyright information about the package.&lt;/p&gt;
&lt;p&gt;You are able to leave this blank, but when packaging the Git-Mastery app, I had opted to instead copy over the &lt;code&gt;LICENSE&lt;/code&gt; of the application, which happens to be the &lt;a href=&quot;https://opensource.org/license/mit&quot;&gt;MIT license&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;debian/rules&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;These provide the rules for installation, including how/where the application should be installed.&lt;/p&gt;
&lt;p&gt;The file format is that of a &lt;a href=&quot;https://makefiletutorial.com/&quot;&gt;Makefile&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;makefile&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;#!/usr/bin/make -f&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        dh &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;$@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;override_dh_auto_install&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        install -D -m 0755 gitmastery-7.1.2-linux-arm64 debian/gitmastery/usr/bin/gitmastery&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While the official installation guide starts with a rather sparse file (that they build upon):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;makefile&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;#!/usr/bin/make -f&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        dh &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;$@&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have found - through experimentation - that the binary package will not work unless you provide the &lt;code&gt;override_dh_auto_install&lt;/code&gt; step (&lt;a href=&quot;https://www.debian.org/doc/manuals/maint-guide/dreq.en.html#rules&quot;&gt;more information&lt;/a&gt;) where you need to specify how and where the application is getting installed using the &lt;code&gt;install&lt;/code&gt; (&lt;a href=&quot;https://man7.org/linux/man-pages/man1/install.1.html&quot;&gt;man&lt;/a&gt;) command.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-D&lt;/code&gt;: create all leading components of the destination except the last (i.e. create all sub-folders) and then copy the source to the destination&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m 0755&lt;/code&gt;: set the permission mode&lt;/li&gt;
&lt;li&gt;&lt;code&gt;debian/gitmastery/usr/bin/gitmastery&lt;/code&gt;: the leading &lt;code&gt;debian/gitmastery&lt;/code&gt; is necessary because it indicates the &lt;a href=&quot;https://wiki.debian.org/FakeRoot&quot;&gt;fakeroot&lt;/a&gt; before packaging; the ultimate path upon installation is &lt;code&gt;/usr/bin/gitmastery&lt;/code&gt; (this can be verified upon installation).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;debian/$NAME.dirs&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This serves as a directory declaration file used by the &lt;code&gt;dh_installdirs&lt;/code&gt; (&lt;a href=&quot;https://man7.org/linux/man-pages/man1/dh_installdirs.1.html&quot;&gt;man&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For the Git-Mastery, I have left it blank, but if you create your file as &lt;code&gt;debian/test.dirs&lt;/code&gt;, and specify a path &lt;code&gt;usr/bin&lt;/code&gt;, it would then create &lt;code&gt;debian/test/usr/bin&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;debian/source/format&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This specifies the version number for the &lt;a href=&quot;https://debian-handbook.info/browse/stable/sect.source-package-structure.html&quot;&gt;format of the source package&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;makefile&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;3.0 (quilt)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;quilt&lt;/code&gt; (&lt;a href=&quot;https://perl-team.pages.debian.net/howto/quilt.html&quot;&gt;docs&lt;/a&gt;) is used to manage patches to Debian packages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;debian/source/include-binaries&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Given that we’re directly installing the binary, we need to provide its path in this file.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;makefile&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gitmastery-7.1.2-linux-arm64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;creating-the-deb-file&quot;&gt;Creating the &lt;code&gt;.deb&lt;/code&gt; file&lt;/h2&gt;
&lt;p&gt;That is all the files we really need to package the application.&lt;/p&gt;
&lt;p&gt;With this, we can finally package the application:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;dpkg-buildpackage&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -us&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -uc&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; arm64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You want to run this command in the root of your directory, not within &lt;code&gt;debian/&lt;/code&gt;!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-us&lt;/code&gt;: do not sign the source package&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-uc&lt;/code&gt;: do not sign the &lt;code&gt;.buildinfo&lt;/code&gt; and &lt;code&gt;.changes&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-a arm74&lt;/code&gt;: specify the architecture&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This produces the &lt;code&gt;.deb&lt;/code&gt; file with the name &lt;code&gt;&amp;#x3C;NAME&gt;_&amp;#x3C;VERSION&gt;-1_&amp;#x3C;ARCHITECTURE&gt;.deb&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can verify the package using &lt;code&gt;sudo dpkg -i &amp;#x3C;package&gt;&lt;/code&gt;. Once installed, you can also check to confirm where the binary was installed using &lt;code&gt;which gitmastery&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, if all you wanted to do was to create a one-off &lt;code&gt;.deb&lt;/code&gt; and share it with someone directly, you’re done! Congratulations 🎉!&lt;/p&gt;
&lt;p&gt;But if you want to publish this &lt;code&gt;.deb&lt;/code&gt; to a Debian repository for the &lt;code&gt;apt&lt;/code&gt; package manager or automate the entire process, read on!&lt;/p&gt;
&lt;h2 id=&quot;setting-up-the-debian-repository-using-reprepro&quot;&gt;Setting up the Debian repository using &lt;code&gt;reprepro&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;reprepro&lt;/code&gt; (&lt;a href=&quot;https://github.com/ionos-cloud/reprepro&quot;&gt;repository&lt;/a&gt;) is used to create a &lt;a href=&quot;https://wiki.debian.org/DebianRepository&quot;&gt;Debian repository&lt;/a&gt;, but it also works well to host your package so that it is discoverable by through the &lt;code&gt;apt&lt;/code&gt; package manager via &lt;a href=&quot;https://documentation.ubuntu.com/server/explanation/software/third-party-repository-usage/#dealing-with-third-party-apt-repositories-in-ubuntu&quot;&gt;third-party repositories&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As a Debian repository is just a set of files organized in a special directory tree with different infrastructure files, it can be hosted through a static site platform like &lt;a href=&quot;https://docs.github.com/en/pages&quot;&gt;GitHub Pages&lt;/a&gt;. But before we get ahead of ourselves with hosting, let’s figure out how to first generate the necessary files.&lt;/p&gt;
&lt;p&gt;I had initially followed this wonderful guide on the DigitalOcean community tutorial blog on “&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-use-reprepro-for-a-secure-package-repository-on-ubuntu-14-04&quot;&gt;How to Use Reprepro for a Secure Package Repository on Ubuntu 14.04&lt;/a&gt;” but I have adapted it for my (and hopefully your) use case!&lt;/p&gt;
&lt;p&gt;Install &lt;code&gt;reprepro&lt;/code&gt; on your machine.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;apt-get&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;apt-get&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; reprepro&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, create a folder to store the files:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; repo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x26;&amp;#x26; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; repo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, we can start the process of setting up the Debian repository.&lt;/p&gt;
&lt;p&gt;Create a &lt;a href=&quot;https://www.gnupg.org/faq/gnupg-faq.html&quot;&gt;GPG key&lt;/a&gt;. If you already have a GPG key, you might find &lt;a href=&quot;https://superuser.com/questions/1683772/should-i-create-separate-gpg-key-pairs-or-just-one-gpg-key-pair-for-multiple-use&quot;&gt;this discussion&lt;/a&gt; useful in deciding if you should generate another one just for publishing your package, or you can consider &lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-use-reprepro-for-a-secure-package-repository-on-ubuntu-14-04#generate-a-subkey-for-package-signing&quot;&gt;using a subkey&lt;/a&gt; instead.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --gen-key&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;List the key.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --list-secret-key&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The returned value will include your key which we will refer to from here on out as &lt;code&gt;&amp;#x3C;key&gt;&lt;/code&gt; .&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[keyboxd]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;---------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sec   ed25519 2025-07-04 [SC] [expires: 2028-07-03]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;key&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;uid           [ultimate] Jiahao, Woo &amp;#x3C;woojiahao1234@gmail.com&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ssb   cv25519 2025-07-04 [E] [expires: 2028-07-03]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, within &lt;code&gt;repo/&lt;/code&gt;, create a &lt;code&gt;conf/&lt;/code&gt; folder.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create a &lt;code&gt;repo/conf/distributions&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Origin:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; GitHub&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Label:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; GitHub&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Git-Mastery&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Suite:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; stable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Codename:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; any&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Components:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Architectures:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; arm64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SignWith:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ke&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Origin&lt;/code&gt; / &lt;code&gt;Label&lt;/code&gt; / &lt;code&gt;Description&lt;/code&gt;: free-form text displayed to the user or used for pinning&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Suite&lt;/code&gt;: &lt;code&gt;stable&lt;/code&gt; or &lt;code&gt;testing&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Architectures&lt;/code&gt;: space-separated list of &lt;a href=&quot;https://wiki.debian.org/Multiarch/Tuples#Architectures_in_Debian&quot;&gt;Debian architecture names&lt;/a&gt;; for now, we’re only publishing to the &lt;code&gt;arm64&lt;/code&gt; architecture (we will explore how to &lt;a href=&quot;#multi-architecture-publishing&quot;&gt;support multi-architecture packages later&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SignWith&lt;/code&gt;: signing fingerprint from the PGP certificate above using &lt;code&gt;&amp;#x3C;key&gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, you can start to add packages to your repository. For the Git-Mastery app, because we store the generated &lt;code&gt;.deb&lt;/code&gt; packages as &lt;a href=&quot;https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases&quot;&gt;release artifacts&lt;/a&gt;, we need an additional step to download the files onto the local machine, but if you have the &lt;code&gt;.deb&lt;/code&gt; package on hand, you can just use it directly.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -L&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; https://github.com/git-mastery/app/releases/download/v7.1.2/gitmastery_7.1.2-1_arm64.deb&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gitmastery_7.1.2-1_arm64.deb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this package, use &lt;code&gt;debsigs&lt;/code&gt; (&lt;a href=&quot;https://manpages.debian.org/unstable/debsigs/debsigs.1p.en.html&quot;&gt;man&lt;/a&gt;) to crytographically sign it using the GPG key created earlier:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;debsigs&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  --gpgopts=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;--batch --no-tty --pinentry-mode=loopback&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  --sign=origin&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  --default-key=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&amp;#x3C;key&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  gitmastery_7.1.2-1_arm64.deb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--gpgopts&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--batch&lt;/code&gt;: non-interactive mode&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--no-tty&lt;/code&gt;: don’t use the terminal&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--pinentry-mode=loopback&lt;/code&gt;: allow passphrase input programmatically&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--sign=origin&lt;/code&gt;: creates an &lt;a href=&quot;https://manpages.debian.org/unstable/debsigs/debsigs.1p.en.html#SIGNATURE_TYPES&quot;&gt;origin signature&lt;/a&gt; that indicates that it is the official signature of the organization that distributes the package (although you might use &lt;code&gt;maint&lt;/code&gt; instead)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--default-key=&quot;&amp;#x3C;key&gt;&quot;&lt;/code&gt;: uses the GPG key created&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, add the signed &lt;code&gt;.deb&lt;/code&gt; to the Debian repository using &lt;code&gt;reprepro&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reprepro&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -Vb&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; repo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; includedeb&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;gitmastery_7.1.2-1_arm64.deb&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-Vb repo&lt;/code&gt;: verbose and use the &lt;code&gt;repo&lt;/code&gt; folder as the base directory&lt;/li&gt;
&lt;li&gt;&lt;code&gt;includedeb&lt;/code&gt;: command to insert the &lt;code&gt;.deb&lt;/code&gt; into the repository and update the metadata&lt;/li&gt;
&lt;li&gt;&lt;code&gt;any&lt;/code&gt;: target distribution&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This creates the necessary files for the Debian repository to host and publish the &lt;code&gt;.deb&lt;/code&gt; package you had just included.&lt;/p&gt;
&lt;p&gt;Then, copy your GPG public key over into &lt;code&gt;repo/&lt;/code&gt; along with creating an empty &lt;code&gt;index.html&lt;/code&gt; file.&lt;/p&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;You can copy your GPG public key to a file named &lt;code&gt;pubkey.gpg&lt;/code&gt; via&lt;/p&gt;&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --output&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; pubkey.gpg&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --armor&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;emai&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;l&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;publishing-the-debian-repository-to-github-pages&quot;&gt;Publishing the Debian repository to GitHub Pages&lt;/h2&gt;
&lt;p&gt;As mentioned before, a Debian repository is just a set of files with some set of special infrastructure files. So you can host it on a static site hosting platform like GitHub Pages.&lt;/p&gt;
&lt;p&gt;To do so, initialize &lt;code&gt;repo&lt;/code&gt; as a Git repository.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; init&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, create a GitHub repository and add it as a remote to the local Git repository.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; remote&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; origin&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; https://github.com/woojiahao/demo-apt-repo.git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add all of the generated files in a commit.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x26;&amp;#x26; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Setup Debian repository&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Push the changes to the repository.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; push&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; origin&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, &lt;a href=&quot;https://docs.github.com/en/pages/quickstart&quot;&gt;enable GitHub Pages on the repository&lt;/a&gt; and GitHub should handle the rest.&lt;/p&gt;
&lt;p&gt;You should then be able to install the package from the repository.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Set-up to recognize the Debian repository as a trusted source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;deb [trusted=yes] https://git-mastery.github.io/gitmastery-apt-repo any main&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; tee&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; /etc/apt/sources.list.d/gitmastery.list&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; /dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; apt&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; software-properties-common&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; add-apt-repository&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;deb https://git-mastery.github.io/gitmastery-apt-repo any main&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Installing the package&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; apt&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; apt-get&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gitmastery&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember to substitute your username and repository name accordingly!&lt;/p&gt;
&lt;p&gt;Amazing, we are able to now install the package from the new Debian repository, so users can avoid directly downloading your &lt;code&gt;.deb&lt;/code&gt; package just to try your package.&lt;/p&gt;
&lt;p&gt;This just leaves two big questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How do we support multiple architectures?&lt;/li&gt;
&lt;li&gt;How do we automate this process?&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;multi-architecture-support&quot;&gt;Multi-architecture support&lt;/h2&gt;
&lt;p&gt;Supporting multiple architectures is actually a lot simpler once you understand the packaging and publishing steps.&lt;/p&gt;
&lt;h3 id=&quot;multi-architecture-packaging&quot;&gt;Multi-architecture packaging&lt;/h3&gt;
&lt;p&gt;To create package your application for multiple architectures, you will need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create multiple executables for each architecture&lt;/li&gt;
&lt;li&gt;Create an upstream tarball for each architecture&lt;/li&gt;
&lt;li&gt;Update the &lt;code&gt;Architecture&lt;/code&gt; field in the &lt;code&gt;debian/control&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Update the executable path in the &lt;code&gt;debian/rules&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Update the executable name in the &lt;code&gt;debian/source/include-binaries&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;When running the &lt;code&gt;dpkg-buildpackage&lt;/code&gt; command, pass the architecture to the &lt;code&gt;-a&lt;/code&gt; flag&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These changes should generate a new &lt;code&gt;.deb&lt;/code&gt; file for the new architecture.&lt;/p&gt;
&lt;h3 id=&quot;multi-architecture-publishing&quot;&gt;Multi-architecture publishing&lt;/h3&gt;
&lt;p&gt;With this new &lt;code&gt;.deb&lt;/code&gt; file and you can sign it and add it to the Debian repository.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add the new architecture to the &lt;code&gt;Architectures&lt;/code&gt; field in &lt;code&gt;repo/conf/distributions&lt;/code&gt; field&lt;/li&gt;
&lt;li&gt;Sign the new &lt;code&gt;.deb&lt;/code&gt; file with &lt;code&gt;debsigs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Run the same &lt;code&gt;reprepro&lt;/code&gt; command again (with no changes!)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This should generate the necessary files for your Debian repository. Remember to commit these changes and push them, and let GitHub Pages do the rest.&lt;/p&gt;
&lt;p&gt;Now, depending on your user’s architecture, the Debian repository should be able to intelligently download the appropriate signed &lt;code&gt;.deb&lt;/code&gt; package for that architecture.&lt;/p&gt;
&lt;p&gt;Let’s now wrap everything up and see how we can automate this entire process using GitHub Actions so that it triggers when a new tag is pushed.&lt;/p&gt;
&lt;h2 id=&quot;automating-the-packaging-and-publish-process&quot;&gt;Automating the packaging and publish process&lt;/h2&gt;
&lt;p&gt;For this, you will need two GitHub repositories:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The source repository that contains your application code&lt;/li&gt;
&lt;li&gt;The Debian repository&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You should already be working with the first, but you may need to create the second (note that if you were following along, you might need a new repository for this portion).&lt;/p&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;If you are new to GitHub Actions and need an introduction, I have given a &lt;a href=&quot;https://youtu.be/jnUk9YABcrE?si=caqWq-HbVHzOQ-xJ&quot;&gt;talk on CI/CD with GitHub Actions&lt;/a&gt; along with a &lt;a href=&quot;https://wiki.nushackers.org/hackerschool/ci-cd-with-github-actions&quot;&gt;guide on the contents covered&lt;/a&gt;!&lt;/p&gt;&lt;/div&gt;
&lt;h3 id=&quot;setting-up-the-source-repository&quot;&gt;Setting up the source repository&lt;/h3&gt;
&lt;p&gt;Create a new workflow file in your source repository under &lt;code&gt;.github/workflows&lt;/code&gt; and you can name it whatever you want. I chose to name the one for Git-Mastery &lt;code&gt;publish.yml&lt;/code&gt; (&lt;a href=&quot;https://github.com/git-mastery/app/blob/main/.github/workflows/publish.yml&quot;&gt;workflow file&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;To automatically package your application on tag, you can use the workflow trigger action of &lt;code&gt;push&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Build and release Git-Mastery CLI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  workflow_dispatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    tags&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;v*.*.*&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you will need three jobs to run in sequence:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Building the Linux executables for both AMD64 and ARM64&lt;/li&gt;
&lt;li&gt;Building the &lt;code&gt;.deb&lt;/code&gt; packages per architecture&lt;/li&gt;
&lt;li&gt;Triggering the publish job&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Building the Linux executable for both AMD64 and ARM64&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To build the Linux executables for both AMD64 and ARM64, we can use a &lt;a href=&quot;https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/run-job-variations&quot;&gt;matrix in GitHub Actions&lt;/a&gt; to run the same job on both an &lt;code&gt;amd64&lt;/code&gt; and &lt;code&gt;arm64&lt;/code&gt; runner.&lt;/p&gt;
&lt;p&gt;Then, the steps are relatively straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Checkout the current source repository&lt;/li&gt;
&lt;li&gt;Setup the necessary dependencies to build the application (Python 3.13 for Git-Mastery and using the libraries in &lt;code&gt;requirements.txt&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Extracting the &lt;code&gt;ARCHITECTURE&lt;/code&gt; and &lt;code&gt;FILENAME&lt;/code&gt; from the matrix information&lt;/li&gt;
&lt;li&gt;Build the actual binary (using &lt;code&gt;pyinstaller&lt;/code&gt; for Git-Mastery)&lt;/li&gt;
&lt;li&gt;Create a GitHub release with the generated binary&lt;/li&gt;
&lt;li&gt;Publish the generated binary as a &lt;a href=&quot;https://docs.github.com/en/actions/concepts/workflows-and-actions/workflow-artifacts&quot;&gt;workflow artifact&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We use a workflow artifact because it can be shared across jobs within the same workflow, reducing the need for us to directly access the release files.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  linux-build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    strategy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      matrix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        os&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ubuntu-24.04-arm&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    runs-on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ matrix.os }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Checkout source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Set up Python&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/setup-python@v5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          python-version&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;3.13&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Install dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          python -m pip install --upgrade pip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          pip install -r requirements.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Get binary name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        id&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;binary-name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          OS_VERSION&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ matrix.os }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          if [ $OS_VERSION = &quot;ubuntu-latest&quot; ]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            ARCHITECTURE=amd64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            ARCHITECTURE=arm64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          FILENAME=gitmastery-${GITHUB_REF_NAME#v}-linux-$ARCHITECTURE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;binary=$FILENAME&quot; &gt;&gt; $GITHUB_OUTPUT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Build binary&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          BINARY_NAME&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ steps.binary-name.outputs.binary }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;__version__ = \&quot;${GITHUB_REF_NAME}\&quot;&quot; &gt; app/version.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          pyinstaller --onefile main.py --name $BINARY_NAME&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Create GitHub Release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;softprops/action-gh-release@v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          files&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;dist/${{ steps.binary-name.outputs.binary }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          GITHUB_TOKEN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Publish package as artifact&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/upload-artifact@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ steps.binary-name.outputs.binary }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          path&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;dist/${{ steps.binary-name.outputs.binary }}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Building the &lt;code&gt;.deb&lt;/code&gt; packages per architecture&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Then, we declare the next job that requires the &lt;code&gt;linux-build&lt;/code&gt; job from above to start. We use a matrix again to build the &lt;code&gt;.deb&lt;/code&gt; on each architecture.&lt;/p&gt;
&lt;p&gt;These steps follow how we regularly package the &lt;code&gt;.deb&lt;/code&gt; , except this time, we care a little more about where we store the files for publishing:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Extracting the &lt;code&gt;ARCHITECTURE&lt;/code&gt; and &lt;code&gt;FILENAME&lt;/code&gt; from the matrix information&lt;/li&gt;
&lt;li&gt;Install the necessary dependencies on the runner&lt;/li&gt;
&lt;li&gt;Create the root folder as discussed above&lt;/li&gt;
&lt;li&gt;Create the upstream tarball&lt;/li&gt;
&lt;li&gt;Create the files for &lt;code&gt;debian/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Build the &lt;code&gt;.deb&lt;/code&gt; using &lt;code&gt;dpkg-buildpackage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Add the &lt;code&gt;.deb&lt;/code&gt; to the GitHub release&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note that when we generate the &lt;code&gt;debian/rules&lt;/code&gt; file this way, we need to preserve all the tabs and newlines accordingly, so we use &lt;code&gt;echo -e&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We also do not need to publish any workflow artifacts as there are no more downstream jobs that will use these files.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  linux-build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  debian-build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    needs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;linux-build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    strategy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      matrix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        os&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ubuntu-24.04-arm&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    runs-on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ matrix.os }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Checkout source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          path&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;app&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Extract variables&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          ARCHITECTURE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ matrix.architecture }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          OS_VERSION&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ matrix.os }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          if [ $OS_VERSION = &quot;ubuntu-latest&quot; ]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            ARCHITECTURE=amd64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            ARCHITECTURE=arm64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;VERSION=${GITHUB_REF_NAME#v}&quot; &gt;&gt; $GITHUB_ENV&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;ARCHITECTURE=${ARCHITECTURE}&quot; &gt;&gt; $GITHUB_ENV&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Get the tag&apos;s commit message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          cd app/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          CHANGELOG_MESSAGE=$(git show ${GITHUB_REF_NAME} --no-patch --pretty=format:%s)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;CHANGELOG_MESSAGE=${CHANGELOG_MESSAGE}&quot; &gt;&gt; $GITHUB_ENV&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Install Debian packaging tools&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          sudo apt-get install devscripts build-essential debhelper-compat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Create folder structure for ${{ env.ARCHITECTURE }} distribution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          mkdir gitmastery-${VERSION}-${ARCHITECTURE}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Download ${{ env.ARCHITECTURE }} binaries from artifacts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/download-artifact@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;gitmastery-${{ env.VERSION }}-linux-${{ env.ARCHITECTURE }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          path&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;gitmastery-${{ env.VERSION }}-${{ env.ARCHITECTURE }}/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Create upstream tarball .orig.tar.gz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Create .orig.tar.gz file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          tar -czf gitmastery_${VERSION}.orig.tar.gz gitmastery-${VERSION}-${ARCHITECTURE}/gitmastery-${VERSION}-linux-${ARCHITECTURE}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Generate Debian packaging files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        working-directory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;gitmastery-${{ env.VERSION }}-${{ env.ARCHITECTURE }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          EMAIL&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;woojiahao1234@gmail.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          NAME&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Jiahao, Woo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          file gitmastery-${VERSION}-linux-${ARCHITECTURE}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Create the debian folder&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          mkdir debian&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Generate the changelog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          dch --create -v ${VERSION}-1 -u low --package gitmastery &quot;$CHANGELOG_MESSAGE&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Create the control file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;&quot;&quot;Source: gitmastery&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Maintainer: $NAME &amp;#x3C;$EMAIL&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Section: misc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Priority: optional&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Standards-Version: 4.7.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Build-Depends: debhelper-compat (= 13)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Package: gitmastery&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Architecture: ${ARCHITECTURE}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Depends: ${shlibs:Depends}, ${misc:Depends}, libc6 (&gt;= 2.35), python3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Description: execute Git-Mastery&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            gitmastery is a Git learning tool built by the National University of Singapore School of Computing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;&quot;&quot; &gt; debian/control&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Copy over the MIT license from the main app to this release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          cat ../app/LICENSE &gt; debian/copyright&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          mkdir debian/source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;3.0 (quilt)&quot; &gt; debian/source/format&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Provide the rules for installation, using -e to preserve the tab character as per:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # https://wiki.debian.org/Packaging/Intro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo -e $&quot;&quot;&quot;#!/usr/bin/make -f&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          %:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          \tdh \$@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          \n&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          override_dh_auto_install:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          \tinstall -D -m 0755 gitmastery-${VERSION}-linux-${ARCHITECTURE} debian/gitmastery/usr/bin/gitmastery&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;&quot;&quot; &gt; debian/rules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;&quot;&quot;usr/bin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;&quot;&quot; &gt; debian/gitmastery.dirs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          mkdir -p debian/source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;&quot;&quot;gitmastery-${VERSION}-linux-${ARCHITECTURE}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;&quot;&quot; &gt; debian/source/include-binaries&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Build the package&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          dpkg-buildpackage -us -uc -a ${ARCHITECTURE}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Create GitHub Release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;softprops/action-gh-release@v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          files&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;gitmastery_${{ env.VERSION }}-1_${{ env.ARCHITECTURE }}.deb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          GITHUB_TOKEN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Triggering the publish job&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The final step is to trigger the publish job, taking the generated &lt;code&gt;.deb&lt;/code&gt; packages (stored in the source repository’s GitHub releases) and uploading them to GitHub Pages on the Debian repository.&lt;/p&gt;
&lt;p&gt;For this step, we will simply call the &lt;a href=&quot;https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows&quot;&gt;workflow file&lt;/a&gt; from the other GitHub repository. We pass the &lt;code&gt;github.ref_name&lt;/code&gt; through as a variable since we will need it for versioning the published files.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  linux-build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  debian-build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  debian-publish-apt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    needs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;debian-build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    permissions&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;write-all&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;git-mastery/gitmastery-apt-repo/.github/workflows/debian-apt-repo.yml@main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      version&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ github.ref_name }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    secrets&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;inherit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the entire workflow file, refer to &lt;a href=&quot;#appendix-packaging-workflow&quot;&gt;the appendix below&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;setting-up-the-debian-repository&quot;&gt;Setting up the Debian repository&lt;/h3&gt;
&lt;p&gt;Now, in the Debian repository, create a new workflow file under &lt;code&gt;.github/workflows&lt;/code&gt;. For Git-Mastery, I opted to call it &lt;code&gt;debian-apt-repo.yml&lt;/code&gt; (&lt;a href=&quot;https://github.com/git-mastery/gitmastery-apt-repo/blob/main/.github/workflows/debian-apt-repo.yml&quot;&gt;workflow file&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;There are some additional set-up steps required to work with your generated GPG key:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add the GPG private key to the &lt;a href=&quot;https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets&quot;&gt;GitHub repository’s secrets&lt;/a&gt;, you can retrieve your private key using &lt;code&gt;gpg --armor --export-secret-key&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;callout warning&quot;&gt;&lt;p&gt;For simplicity, the GPG should not require a passphrase, otherwise it will fail when this workflow runs.&lt;/p&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the GPG public key (&lt;code&gt;&amp;#x3C;key&gt;&lt;/code&gt;) to the GitHub repository’s variables&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a blank &lt;code&gt;index.html&lt;/code&gt; to the repository&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the GPG public key file to the repository&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set your &lt;a href=&quot;https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site&quot;&gt;GitHub Pages to publish&lt;/a&gt; from the &lt;code&gt;gh-pages&lt;/code&gt; branch instead&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Then, the rest of the steps are similar to what we have described before.&lt;/p&gt;
&lt;p&gt;The main difference here is that we iterate over both architecture types to support multi-architecture publishing.&lt;/p&gt;
&lt;p&gt;We also use a GitHub workflow to automatically publish the new files under a separate branch &lt;code&gt;gh-pages&lt;/code&gt; instead, treating the &lt;code&gt;main&lt;/code&gt; branch as just a store for the necessary files.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Build &amp;#x26; Publish Debian Package&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  workflow_call&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    inputs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      version&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        required&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  build-and-publish&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    permissions&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      pages&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;write&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      contents&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;write&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    environment&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    runs-on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      DISTRIBUTION&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;any&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      COMPONENT&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      RELEASE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      GPG_PRIVATE_KEY&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ secrets.GPG_PRIVATE_KEY }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      KEY_ID&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ vars.KEY_ID }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      VERSION&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ inputs.version }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Checkout repository&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          repository&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;git-mastery/gitmastery-apt-repo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          token&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          path&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;aptrepo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Install dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          sudo apt-get update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          sudo apt-get install -y reprepro dpkg-dev curl jq gnupg debsigs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Import GPG key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;$GPG_PRIVATE_KEY&quot; | gpg --batch --import&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;$KEY_ID:6:&quot; |  gpg --batch --import-ownertrust --pinentry-mode=loopback&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Setup repository structure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        working-directory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;aptrepo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          mkdir -p repo/conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;Origin: GitHub&quot; &gt;repo/conf/distributions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;Label: GitHub Git-Mastery&quot; &gt;&gt;repo/conf/distributions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;Suite: stable&quot; &gt;&gt;repo/conf/distributions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;Codename: ${DISTRIBUTION}&quot; &gt;&gt;repo/conf/distributions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;Components: ${COMPONENT}&quot; &gt;&gt;repo/conf/distributions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;Architectures: arm64 amd64&quot; &gt;&gt;repo/conf/distributions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;SignWith: $KEY_ID&quot; &gt;&gt;repo/conf/distributions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          cp pubkey.gpg repo/pubkey.gpg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          cp index.html repo/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Add .deb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        working-directory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;aptrepo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          for ARCHITECTURE in &quot;arm64&quot; &quot;amd64&quot;; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            echo &quot;Publishing for $ARCHITECTURE&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            DOWNLOAD_URL=$(curl -s https://api.github.com/repos/git-mastery/app/releases/tags/${VERSION} | jq -r --arg suffix &quot;${ARCHITECTURE}.deb&quot; &apos;.assets[] | select(.name | endswith($suffix)) | .browser_download_url&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            TRIMMED_VERSION=${VERSION#v}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            FILENAME=&quot;gitmastery_${TRIMMED_VERSION}-1_${ARCHITECTURE}.deb&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            TRIMMED_VERSION=${VERSION#v}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            curl -L &quot;$DOWNLOAD_URL&quot; -o $FILENAME&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            debsigs -v --gpgopts=&quot;--batch --no-tty --pinentry-mode=loopback&quot; --sign=origin --default-key=&quot;$KEY_ID&quot; $FILENAME&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            reprepro -Vb repo includedeb ${DISTRIBUTION} &quot;gitmastery_${TRIMMED_VERSION}-${RELEASE}_${ARCHITECTURE}.deb&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Deploy APT repository to GitHub Pages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;peaceiris/actions-gh-pages@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          personal_token&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ secrets.ORG_PAT }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          publish_dir&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;./aptrepo/repo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          external_repository&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;git-mastery/gitmastery-apt-repo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Voilà! You have now created a fully automated package and publishing pipeline!&lt;/p&gt;
&lt;p&gt;Visualizing the pipeline will look like this:&lt;/p&gt;
&lt;img alt=&quot;&quot; height=&quot;710&quot; id=&quot;mermaid-0&quot; src=&quot;data:image/svg+xml,%3csvg id=&amp;#x27;mermaid-0&amp;#x27; width=&amp;#x27;100%25&amp;#x27; xmlns=&amp;#x27;http://www.w3.org/2000/svg&amp;#x27; xmlns:xlink=&amp;#x27;http://www.w3.org/1999/xlink&amp;#x27; class=&amp;#x27;flowchart&amp;#x27; style=&amp;#x27;max-width: 586px%3b&amp;#x27; viewBox=&amp;#x27;0 0 586 710&amp;#x27; role=&amp;#x27;graphics-document document&amp;#x27; aria-roledescription=&amp;#x27;flowchart-v2&amp;#x27;%3e%3cstyle%3e%23mermaid-0%7bfont-family:arial%2csans-serif%3bfont-size:16px%3bfill:%23333%3b%7d%40keyframes edge-animation-frame%7bfrom%7bstroke-dashoffset:0%3b%7d%7d%40keyframes dash%7bto%7bstroke-dashoffset:0%3b%7d%7d%23mermaid-0 .edge-animation-slow%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 50s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-0 .edge-animation-fast%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 20s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-0 .error-icon%7bfill:%23552222%3b%7d%23mermaid-0 .error-text%7bfill:%23552222%3bstroke:%23552222%3b%7d%23mermaid-0 .edge-thickness-normal%7bstroke-width:1px%3b%7d%23mermaid-0 .edge-thickness-thick%7bstroke-width:3.5px%3b%7d%23mermaid-0 .edge-pattern-solid%7bstroke-dasharray:0%3b%7d%23mermaid-0 .edge-thickness-invisible%7bstroke-width:0%3bfill:none%3b%7d%23mermaid-0 .edge-pattern-dashed%7bstroke-dasharray:3%3b%7d%23mermaid-0 .edge-pattern-dotted%7bstroke-dasharray:2%3b%7d%23mermaid-0 .marker%7bfill:%23333333%3bstroke:%23333333%3b%7d%23mermaid-0 .marker.cross%7bstroke:%23333333%3b%7d%23mermaid-0 svg%7bfont-family:arial%2csans-serif%3bfont-size:16px%3b%7d%23mermaid-0 p%7bmargin:0%3b%7d%23mermaid-0 .label%7bfont-family:arial%2csans-serif%3bcolor:%23333%3b%7d%23mermaid-0 .cluster-label text%7bfill:%23333%3b%7d%23mermaid-0 .cluster-label span%7bcolor:%23333%3b%7d%23mermaid-0 .cluster-label span p%7bbackground-color:transparent%3b%7d%23mermaid-0 .label text%2c%23mermaid-0 span%7bfill:%23333%3bcolor:%23333%3b%7d%23mermaid-0 .node rect%2c%23mermaid-0 .node circle%2c%23mermaid-0 .node ellipse%2c%23mermaid-0 .node polygon%2c%23mermaid-0 .node path%7bfill:%23ECECFF%3bstroke:%239370DB%3bstroke-width:1px%3b%7d%23mermaid-0 .rough-node .label text%2c%23mermaid-0 .node .label text%2c%23mermaid-0 .image-shape .label%2c%23mermaid-0 .icon-shape .label%7btext-anchor:middle%3b%7d%23mermaid-0 .node .katex path%7bfill:black%3bstroke:black%3bstroke-width:1px%3b%7d%23mermaid-0 .rough-node .label%2c%23mermaid-0 .node .label%2c%23mermaid-0 .image-shape .label%2c%23mermaid-0 .icon-shape .label%7btext-align:center%3b%7d%23mermaid-0 .node.clickable%7bcursor:pointer%3b%7d%23mermaid-0 .root .anchor path%7bfill:%23333333!important%3bstroke-width:0%3bstroke:%23333333%3b%7d%23mermaid-0 .arrowheadPath%7bfill:%23333333%3b%7d%23mermaid-0 .edgePath .path%7bstroke:%23333333%3bstroke-width:2.0px%3b%7d%23mermaid-0 .flowchart-link%7bstroke:%23333333%3bfill:none%3b%7d%23mermaid-0 .edgeLabel%7bbackground-color:rgba(232%2c232%2c232%2c 0.8)%3btext-align:center%3b%7d%23mermaid-0 .edgeLabel p%7bbackground-color:rgba(232%2c232%2c232%2c 0.8)%3b%7d%23mermaid-0 .edgeLabel rect%7bopacity:0.5%3bbackground-color:rgba(232%2c232%2c232%2c 0.8)%3bfill:rgba(232%2c232%2c232%2c 0.8)%3b%7d%23mermaid-0 .labelBkg%7bbackground-color:rgba(232%2c 232%2c 232%2c 0.5)%3b%7d%23mermaid-0 .cluster rect%7bfill:%23ffffde%3bstroke:%23aaaa33%3bstroke-width:1px%3b%7d%23mermaid-0 .cluster text%7bfill:%23333%3b%7d%23mermaid-0 .cluster span%7bcolor:%23333%3b%7d%23mermaid-0 div.mermaidTooltip%7bposition:absolute%3btext-align:center%3bmax-width:200px%3bpadding:2px%3bfont-family:arial%2csans-serif%3bfont-size:12px%3bbackground:hsl(80%2c 100%25%2c 96.2745098039%25)%3bborder:1px solid %23aaaa33%3bborder-radius:2px%3bpointer-events:none%3bz-index:100%3b%7d%23mermaid-0 .flowchartTitleText%7btext-anchor:middle%3bfont-size:18px%3bfill:%23333%3b%7d%23mermaid-0 rect.text%7bfill:none%3bstroke-width:0%3b%7d%23mermaid-0 .icon-shape%2c%23mermaid-0 .image-shape%7bbackground-color:rgba(232%2c232%2c232%2c 0.8)%3btext-align:center%3b%7d%23mermaid-0 .icon-shape p%2c%23mermaid-0 .image-shape p%7bbackground-color:rgba(232%2c232%2c232%2c 0.8)%3bpadding:2px%3b%7d%23mermaid-0 .icon-shape rect%2c%23mermaid-0 .image-shape rect%7bopacity:0.5%3bbackground-color:rgba(232%2c232%2c232%2c 0.8)%3bfill:rgba(232%2c232%2c232%2c 0.8)%3b%7d%23mermaid-0 .label-icon%7bdisplay:inline-block%3bheight:1em%3boverflow:visible%3bvertical-align:-0.125em%3b%7d%23mermaid-0 .node .label-icon path%7bfill:currentColor%3bstroke:revert%3bstroke-width:revert%3b%7d%23mermaid-0 :root%7b--mermaid-font-family:arial%2csans-serif%3b%7d%3c/style%3e%3cg%3e%3cmarker id=&amp;#x27;mermaid-0_flowchart-v2-pointEnd&amp;#x27; class=&amp;#x27;marker flowchart-v2&amp;#x27; viewBox=&amp;#x27;0 0 10 10&amp;#x27; refX=&amp;#x27;5&amp;#x27; refY=&amp;#x27;5&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;8&amp;#x27; markerHeight=&amp;#x27;8&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3cpath d=&amp;#x27;M 0 0 L 10 5 L 0 10 z&amp;#x27; class=&amp;#x27;arrowMarkerPath&amp;#x27; style=&amp;#x27;stroke-width: 1%3b stroke-dasharray: 1%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3cmarker id=&amp;#x27;mermaid-0_flowchart-v2-pointStart&amp;#x27; class=&amp;#x27;marker flowchart-v2&amp;#x27; viewBox=&amp;#x27;0 0 10 10&amp;#x27; refX=&amp;#x27;4.5&amp;#x27; refY=&amp;#x27;5&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;8&amp;#x27; markerHeight=&amp;#x27;8&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3cpath d=&amp;#x27;M 0 5 L 10 10 L 10 0 z&amp;#x27; class=&amp;#x27;arrowMarkerPath&amp;#x27; style=&amp;#x27;stroke-width: 1%3b stroke-dasharray: 1%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3cmarker id=&amp;#x27;mermaid-0_flowchart-v2-circleEnd&amp;#x27; class=&amp;#x27;marker flowchart-v2&amp;#x27; viewBox=&amp;#x27;0 0 10 10&amp;#x27; refX=&amp;#x27;11&amp;#x27; refY=&amp;#x27;5&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;11&amp;#x27; markerHeight=&amp;#x27;11&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3ccircle cx=&amp;#x27;5&amp;#x27; cy=&amp;#x27;5&amp;#x27; r=&amp;#x27;5&amp;#x27; class=&amp;#x27;arrowMarkerPath&amp;#x27; style=&amp;#x27;stroke-width: 1%3b stroke-dasharray: 1%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3cmarker id=&amp;#x27;mermaid-0_flowchart-v2-circleStart&amp;#x27; class=&amp;#x27;marker flowchart-v2&amp;#x27; viewBox=&amp;#x27;0 0 10 10&amp;#x27; refX=&amp;#x27;-1&amp;#x27; refY=&amp;#x27;5&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;11&amp;#x27; markerHeight=&amp;#x27;11&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3ccircle cx=&amp;#x27;5&amp;#x27; cy=&amp;#x27;5&amp;#x27; r=&amp;#x27;5&amp;#x27; class=&amp;#x27;arrowMarkerPath&amp;#x27; style=&amp;#x27;stroke-width: 1%3b stroke-dasharray: 1%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3cmarker id=&amp;#x27;mermaid-0_flowchart-v2-crossEnd&amp;#x27; class=&amp;#x27;marker cross flowchart-v2&amp;#x27; viewBox=&amp;#x27;0 0 11 11&amp;#x27; refX=&amp;#x27;12&amp;#x27; refY=&amp;#x27;5.2&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;11&amp;#x27; markerHeight=&amp;#x27;11&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3cpath d=&amp;#x27;M 1%2c1 l 9%2c9 M 10%2c1 l -9%2c9&amp;#x27; class=&amp;#x27;arrowMarkerPath&amp;#x27; style=&amp;#x27;stroke-width: 2%3b stroke-dasharray: 1%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3cmarker id=&amp;#x27;mermaid-0_flowchart-v2-crossStart&amp;#x27; class=&amp;#x27;marker cross flowchart-v2&amp;#x27; viewBox=&amp;#x27;0 0 11 11&amp;#x27; refX=&amp;#x27;-1&amp;#x27; refY=&amp;#x27;5.2&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;11&amp;#x27; markerHeight=&amp;#x27;11&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3cpath d=&amp;#x27;M 1%2c1 l 9%2c9 M 10%2c1 l -9%2c9&amp;#x27; class=&amp;#x27;arrowMarkerPath&amp;#x27; style=&amp;#x27;stroke-width: 2%3b stroke-dasharray: 1%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3cg class=&amp;#x27;root&amp;#x27;%3e%3cg class=&amp;#x27;clusters&amp;#x27;/%3e%3cg class=&amp;#x27;edgePaths&amp;#x27;%3e%3cpath d=&amp;#x27;M163.73%2c62L163.73%2c66.167C163.73%2c70.333%2c163.73%2c78.667%2c163.73%2c86.333C163.73%2c94%2c163.73%2c101%2c163.73%2c104.5L163.73%2c108&amp;#x27; id=&amp;#x27;L_a_c_0&amp;#x27; class=&amp;#x27;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&amp;#x27; style=&amp;#x27;%3b&amp;#x27; data-edge=&amp;#x27;true&amp;#x27; data-et=&amp;#x27;edge&amp;#x27; data-id=&amp;#x27;L_a_c_0&amp;#x27; data-points=&amp;#x27;W3sieCI6MTYzLjczMDQ2ODc1LCJ5Ijo2Mn0seyJ4IjoxNjMuNzMwNDY4NzUsInkiOjg3fSx7IngiOjE2My43MzA0Njg3NSwieSI6MTEyfV0=&amp;#x27; marker-end=&amp;#x27;url(%23mermaid-0_flowchart-v2-pointEnd)&amp;#x27;/%3e%3cpath d=&amp;#x27;M422.27%2c62L422.27%2c66.167C422.27%2c70.333%2c422.27%2c78.667%2c422.27%2c86.333C422.27%2c94%2c422.27%2c101%2c422.27%2c104.5L422.27%2c108&amp;#x27; id=&amp;#x27;L_b_d_0&amp;#x27; class=&amp;#x27;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&amp;#x27; style=&amp;#x27;%3b&amp;#x27; data-edge=&amp;#x27;true&amp;#x27; data-et=&amp;#x27;edge&amp;#x27; data-id=&amp;#x27;L_b_d_0&amp;#x27; data-points=&amp;#x27;W3sieCI6NDIyLjI2OTUzMTI1LCJ5Ijo2Mn0seyJ4Ijo0MjIuMjY5NTMxMjUsInkiOjg3fSx7IngiOjQyMi4yNjk1MzEyNSwieSI6MTEyfV0=&amp;#x27; marker-end=&amp;#x27;url(%23mermaid-0_flowchart-v2-pointEnd)&amp;#x27;/%3e%3cpath d=&amp;#x27;M163.73%2c166L163.73%2c170.167C163.73%2c174.333%2c163.73%2c182.667%2c173.47%2c190.751C183.21%2c198.836%2c202.689%2c206.671%2c212.429%2c210.589L222.168%2c214.507&amp;#x27; id=&amp;#x27;L_c_e_0&amp;#x27; class=&amp;#x27;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&amp;#x27; style=&amp;#x27;%3b&amp;#x27; data-edge=&amp;#x27;true&amp;#x27; data-et=&amp;#x27;edge&amp;#x27; data-id=&amp;#x27;L_c_e_0&amp;#x27; data-points=&amp;#x27;W3sieCI6MTYzLjczMDQ2ODc1LCJ5IjoxNjZ9LHsieCI6MTYzLjczMDQ2ODc1LCJ5IjoxOTF9LHsieCI6MjI1Ljg3OTI4MTg1MDk2MTU1LCJ5IjoyMTZ9XQ==&amp;#x27; marker-end=&amp;#x27;url(%23mermaid-0_flowchart-v2-pointEnd)&amp;#x27;/%3e%3cpath d=&amp;#x27;M422.27%2c166L422.27%2c170.167C422.27%2c174.333%2c422.27%2c182.667%2c412.53%2c190.751C402.79%2c198.836%2c383.311%2c206.671%2c373.571%2c210.589L363.832%2c214.507&amp;#x27; id=&amp;#x27;L_d_e_0&amp;#x27; class=&amp;#x27;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&amp;#x27; style=&amp;#x27;%3b&amp;#x27; data-edge=&amp;#x27;true&amp;#x27; data-et=&amp;#x27;edge&amp;#x27; data-id=&amp;#x27;L_d_e_0&amp;#x27; data-points=&amp;#x27;W3sieCI6NDIyLjI2OTUzMTI1LCJ5IjoxNjZ9LHsieCI6NDIyLjI2OTUzMTI1LCJ5IjoxOTF9LHsieCI6MzYwLjEyMDcxODE0OTAzODQ1LCJ5IjoyMTZ9XQ==&amp;#x27; marker-end=&amp;#x27;url(%23mermaid-0_flowchart-v2-pointEnd)&amp;#x27;/%3e%3cpath d=&amp;#x27;M212.75%2c269.923L200.292%2c274.102C187.833%2c278.282%2c162.917%2c286.641%2c150.458%2c294.32C138%2c302%2c138%2c309%2c138%2c312.5L138%2c316&amp;#x27; id=&amp;#x27;L_e_f_0&amp;#x27; class=&amp;#x27;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&amp;#x27; style=&amp;#x27;%3b&amp;#x27; data-edge=&amp;#x27;true&amp;#x27; data-et=&amp;#x27;edge&amp;#x27; data-id=&amp;#x27;L_e_f_0&amp;#x27; data-points=&amp;#x27;W3sieCI6MjEyLjc1LCJ5IjoyNjkuOTIyNTgwNjQ1MTYxM30seyJ4IjoxMzgsInkiOjI5NX0seyJ4IjoxMzgsInkiOjMyMH1d&amp;#x27; marker-end=&amp;#x27;url(%23mermaid-0_flowchart-v2-pointEnd)&amp;#x27;/%3e%3cpath d=&amp;#x27;M373.25%2c269.923L385.708%2c274.102C398.167%2c278.282%2c423.083%2c286.641%2c435.542%2c294.32C448%2c302%2c448%2c309%2c448%2c312.5L448%2c316&amp;#x27; id=&amp;#x27;L_e_g_0&amp;#x27; class=&amp;#x27;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&amp;#x27; style=&amp;#x27;%3b&amp;#x27; data-edge=&amp;#x27;true&amp;#x27; data-et=&amp;#x27;edge&amp;#x27; data-id=&amp;#x27;L_e_g_0&amp;#x27; data-points=&amp;#x27;W3sieCI6MzczLjI1LCJ5IjoyNjkuOTIyNTgwNjQ1MTYxM30seyJ4Ijo0NDgsInkiOjI5NX0seyJ4Ijo0NDgsInkiOjMyMH1d&amp;#x27; marker-end=&amp;#x27;url(%23mermaid-0_flowchart-v2-pointEnd)&amp;#x27;/%3e%3cpath d=&amp;#x27;M138%2c422L138%2c426.167C138%2c430.333%2c138%2c438.667%2c145.899%2c446.707C153.798%2c454.746%2c169.597%2c462.493%2c177.496%2c466.366L185.395%2c470.239&amp;#x27; id=&amp;#x27;L_f_h_0&amp;#x27; class=&amp;#x27;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&amp;#x27; style=&amp;#x27;%3b&amp;#x27; data-edge=&amp;#x27;true&amp;#x27; data-et=&amp;#x27;edge&amp;#x27; data-id=&amp;#x27;L_f_h_0&amp;#x27; data-points=&amp;#x27;W3sieCI6MTM4LCJ5Ijo0MjJ9LHsieCI6MTM4LCJ5Ijo0NDd9LHsieCI6MTg4Ljk4Njg0MjEwNTI2MzE4LCJ5Ijo0NzJ9XQ==&amp;#x27; marker-end=&amp;#x27;url(%23mermaid-0_flowchart-v2-pointEnd)&amp;#x27;/%3e%3cpath d=&amp;#x27;M448%2c422L448%2c426.167C448%2c430.333%2c448%2c438.667%2c440.101%2c446.707C432.202%2c454.746%2c416.403%2c462.493%2c408.504%2c466.366L400.605%2c470.239&amp;#x27; id=&amp;#x27;L_g_h_0&amp;#x27; class=&amp;#x27;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&amp;#x27; style=&amp;#x27;%3b&amp;#x27; data-edge=&amp;#x27;true&amp;#x27; data-et=&amp;#x27;edge&amp;#x27; data-id=&amp;#x27;L_g_h_0&amp;#x27; data-points=&amp;#x27;W3sieCI6NDQ4LCJ5Ijo0MjJ9LHsieCI6NDQ4LCJ5Ijo0NDd9LHsieCI6Mzk3LjAxMzE1Nzg5NDczNjgsInkiOjQ3Mn1d&amp;#x27; marker-end=&amp;#x27;url(%23mermaid-0_flowchart-v2-pointEnd)&amp;#x27;/%3e%3cpath d=&amp;#x27;M293%2c574L293%2c578.167C293%2c582.333%2c293%2c590.667%2c293%2c598.333C293%2c606%2c293%2c613%2c293%2c616.5L293%2c620&amp;#x27; id=&amp;#x27;L_h_i_0&amp;#x27; class=&amp;#x27;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&amp;#x27; style=&amp;#x27;%3b&amp;#x27; data-edge=&amp;#x27;true&amp;#x27; data-et=&amp;#x27;edge&amp;#x27; data-id=&amp;#x27;L_h_i_0&amp;#x27; data-points=&amp;#x27;W3sieCI6MjkzLCJ5Ijo1NzR9LHsieCI6MjkzLCJ5Ijo1OTl9LHsieCI6MjkzLCJ5Ijo2MjR9XQ==&amp;#x27; marker-end=&amp;#x27;url(%23mermaid-0_flowchart-v2-pointEnd)&amp;#x27;/%3e%3c/g%3e%3cg class=&amp;#x27;edgeLabels&amp;#x27;%3e%3cg class=&amp;#x27;edgeLabel&amp;#x27;%3e%3cg class=&amp;#x27;label&amp;#x27; data-id=&amp;#x27;L_a_c_0&amp;#x27; transform=&amp;#x27;translate(0%2c 0)&amp;#x27;%3e%3cforeignObject width=&amp;#x27;0&amp;#x27; height=&amp;#x27;0&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; class=&amp;#x27;labelBkg&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;edgeLabel&amp;#x27;%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;edgeLabel&amp;#x27;%3e%3cg class=&amp;#x27;label&amp;#x27; data-id=&amp;#x27;L_b_d_0&amp;#x27; transform=&amp;#x27;translate(0%2c 0)&amp;#x27;%3e%3cforeignObject width=&amp;#x27;0&amp;#x27; height=&amp;#x27;0&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; class=&amp;#x27;labelBkg&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;edgeLabel&amp;#x27;%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;edgeLabel&amp;#x27;%3e%3cg class=&amp;#x27;label&amp;#x27; data-id=&amp;#x27;L_c_e_0&amp;#x27; transform=&amp;#x27;translate(0%2c 0)&amp;#x27;%3e%3cforeignObject width=&amp;#x27;0&amp;#x27; height=&amp;#x27;0&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; class=&amp;#x27;labelBkg&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;edgeLabel&amp;#x27;%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;edgeLabel&amp;#x27;%3e%3cg class=&amp;#x27;label&amp;#x27; data-id=&amp;#x27;L_d_e_0&amp;#x27; transform=&amp;#x27;translate(0%2c 0)&amp;#x27;%3e%3cforeignObject width=&amp;#x27;0&amp;#x27; height=&amp;#x27;0&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; class=&amp;#x27;labelBkg&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;edgeLabel&amp;#x27;%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;edgeLabel&amp;#x27;%3e%3cg class=&amp;#x27;label&amp;#x27; data-id=&amp;#x27;L_e_f_0&amp;#x27; transform=&amp;#x27;translate(0%2c 0)&amp;#x27;%3e%3cforeignObject width=&amp;#x27;0&amp;#x27; height=&amp;#x27;0&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; class=&amp;#x27;labelBkg&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;edgeLabel&amp;#x27;%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;edgeLabel&amp;#x27;%3e%3cg class=&amp;#x27;label&amp;#x27; data-id=&amp;#x27;L_e_g_0&amp;#x27; transform=&amp;#x27;translate(0%2c 0)&amp;#x27;%3e%3cforeignObject width=&amp;#x27;0&amp;#x27; height=&amp;#x27;0&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; class=&amp;#x27;labelBkg&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;edgeLabel&amp;#x27;%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;edgeLabel&amp;#x27;%3e%3cg class=&amp;#x27;label&amp;#x27; data-id=&amp;#x27;L_f_h_0&amp;#x27; transform=&amp;#x27;translate(0%2c 0)&amp;#x27;%3e%3cforeignObject width=&amp;#x27;0&amp;#x27; height=&amp;#x27;0&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; class=&amp;#x27;labelBkg&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;edgeLabel&amp;#x27;%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;edgeLabel&amp;#x27;%3e%3cg class=&amp;#x27;label&amp;#x27; data-id=&amp;#x27;L_g_h_0&amp;#x27; transform=&amp;#x27;translate(0%2c 0)&amp;#x27;%3e%3cforeignObject width=&amp;#x27;0&amp;#x27; height=&amp;#x27;0&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; class=&amp;#x27;labelBkg&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;edgeLabel&amp;#x27;%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;edgeLabel&amp;#x27;%3e%3cg class=&amp;#x27;label&amp;#x27; data-id=&amp;#x27;L_h_i_0&amp;#x27; transform=&amp;#x27;translate(0%2c 0)&amp;#x27;%3e%3cforeignObject width=&amp;#x27;0&amp;#x27; height=&amp;#x27;0&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; class=&amp;#x27;labelBkg&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;edgeLabel&amp;#x27;%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;nodes&amp;#x27;%3e%3cg class=&amp;#x27;node default&amp;#x27; id=&amp;#x27;flowchart-a-0&amp;#x27; transform=&amp;#x27;translate(163.73046875%2c 35)&amp;#x27;%3e%3crect class=&amp;#x27;basic label-container&amp;#x27; style=&amp;#x27;&amp;#x27; x=&amp;#x27;-103.375&amp;#x27; y=&amp;#x27;-27&amp;#x27; width=&amp;#x27;206.75&amp;#x27; height=&amp;#x27;54&amp;#x27;/%3e%3cg class=&amp;#x27;label&amp;#x27; style=&amp;#x27;&amp;#x27; transform=&amp;#x27;translate(-73.375%2c -12)&amp;#x27;%3e%3crect/%3e%3cforeignObject width=&amp;#x27;146.75&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;nodeLabel&amp;#x27;%3e%3cp%3egenerate arm64 ELF%3c/p%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;node default&amp;#x27; id=&amp;#x27;flowchart-b-1&amp;#x27; transform=&amp;#x27;translate(422.26953125%2c 35)&amp;#x27;%3e%3crect class=&amp;#x27;basic label-container&amp;#x27; style=&amp;#x27;&amp;#x27; x=&amp;#x27;-105.1640625&amp;#x27; y=&amp;#x27;-27&amp;#x27; width=&amp;#x27;210.328125&amp;#x27; height=&amp;#x27;54&amp;#x27;/%3e%3cg class=&amp;#x27;label&amp;#x27; style=&amp;#x27;&amp;#x27; transform=&amp;#x27;translate(-75.1640625%2c -12)&amp;#x27;%3e%3crect/%3e%3cforeignObject width=&amp;#x27;150.328125&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;nodeLabel&amp;#x27;%3e%3cp%3egenerate amd64 ELF%3c/p%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;node default&amp;#x27; id=&amp;#x27;flowchart-c-3&amp;#x27; transform=&amp;#x27;translate(163.73046875%2c 139)&amp;#x27;%3e%3crect class=&amp;#x27;basic label-container&amp;#x27; style=&amp;#x27;&amp;#x27; x=&amp;#x27;-80.2578125&amp;#x27; y=&amp;#x27;-27&amp;#x27; width=&amp;#x27;160.515625&amp;#x27; height=&amp;#x27;54&amp;#x27;/%3e%3cg class=&amp;#x27;label&amp;#x27; style=&amp;#x27;&amp;#x27; transform=&amp;#x27;translate(-50.2578125%2c -12)&amp;#x27;%3e%3crect/%3e%3cforeignObject width=&amp;#x27;100.515625&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;nodeLabel&amp;#x27;%3e%3cp%3eupload artifact%3c/p%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;node default&amp;#x27; id=&amp;#x27;flowchart-d-5&amp;#x27; transform=&amp;#x27;translate(422.26953125%2c 139)&amp;#x27;%3e%3crect class=&amp;#x27;basic label-container&amp;#x27; style=&amp;#x27;&amp;#x27; x=&amp;#x27;-80.2578125&amp;#x27; y=&amp;#x27;-27&amp;#x27; width=&amp;#x27;160.515625&amp;#x27; height=&amp;#x27;54&amp;#x27;/%3e%3cg class=&amp;#x27;label&amp;#x27; style=&amp;#x27;&amp;#x27; transform=&amp;#x27;translate(-50.2578125%2c -12)&amp;#x27;%3e%3crect/%3e%3cforeignObject width=&amp;#x27;100.515625&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;nodeLabel&amp;#x27;%3e%3cp%3eupload artifact%3c/p%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;node default&amp;#x27; id=&amp;#x27;flowchart-e-7&amp;#x27; transform=&amp;#x27;translate(293%2c 243)&amp;#x27;%3e%3crect class=&amp;#x27;basic label-container&amp;#x27; style=&amp;#x27;&amp;#x27; x=&amp;#x27;-80.25&amp;#x27; y=&amp;#x27;-27&amp;#x27; width=&amp;#x27;160.5&amp;#x27; height=&amp;#x27;54&amp;#x27;/%3e%3cg class=&amp;#x27;label&amp;#x27; style=&amp;#x27;&amp;#x27; transform=&amp;#x27;translate(-50.25%2c -12)&amp;#x27;%3e%3crect/%3e%3cforeignObject width=&amp;#x27;100.5&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; style=&amp;#x27;display: table-cell%3b white-space: nowrap%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b&amp;#x27;%3e%3cspan class=&amp;#x27;nodeLabel&amp;#x27;%3e%3cp%3etrigger publish%3c/p%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;node default&amp;#x27; id=&amp;#x27;flowchart-f-11&amp;#x27; transform=&amp;#x27;translate(138%2c 371)&amp;#x27;%3e%3crect class=&amp;#x27;basic label-container&amp;#x27; style=&amp;#x27;&amp;#x27; x=&amp;#x27;-130&amp;#x27; y=&amp;#x27;-51&amp;#x27; width=&amp;#x27;260&amp;#x27; height=&amp;#x27;102&amp;#x27;/%3e%3cg class=&amp;#x27;label&amp;#x27; style=&amp;#x27;&amp;#x27; transform=&amp;#x27;translate(-100%2c -36)&amp;#x27;%3e%3crect/%3e%3cforeignObject width=&amp;#x27;200&amp;#x27; height=&amp;#x27;72&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; style=&amp;#x27;display: table%3b white-space: break-spaces%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b width: 200px%3b&amp;#x27;%3e%3cspan class=&amp;#x27;nodeLabel&amp;#x27;%3e%3cp%3egenerate Debian package structure and build .deb for arm64%3c/p%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;node default&amp;#x27; id=&amp;#x27;flowchart-g-13&amp;#x27; transform=&amp;#x27;translate(448%2c 371)&amp;#x27;%3e%3crect class=&amp;#x27;basic label-container&amp;#x27; style=&amp;#x27;&amp;#x27; x=&amp;#x27;-130&amp;#x27; y=&amp;#x27;-51&amp;#x27; width=&amp;#x27;260&amp;#x27; height=&amp;#x27;102&amp;#x27;/%3e%3cg class=&amp;#x27;label&amp;#x27; style=&amp;#x27;&amp;#x27; transform=&amp;#x27;translate(-100%2c -36)&amp;#x27;%3e%3crect/%3e%3cforeignObject width=&amp;#x27;200&amp;#x27; height=&amp;#x27;72&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; style=&amp;#x27;display: table%3b white-space: break-spaces%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b width: 200px%3b&amp;#x27;%3e%3cspan class=&amp;#x27;nodeLabel&amp;#x27;%3e%3cp%3egenerate Debian package structure and build .deb for amd64%3c/p%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;node default&amp;#x27; id=&amp;#x27;flowchart-h-15&amp;#x27; transform=&amp;#x27;translate(293%2c 523)&amp;#x27;%3e%3crect class=&amp;#x27;basic label-container&amp;#x27; style=&amp;#x27;&amp;#x27; x=&amp;#x27;-130&amp;#x27; y=&amp;#x27;-51&amp;#x27; width=&amp;#x27;260&amp;#x27; height=&amp;#x27;102&amp;#x27;/%3e%3cg class=&amp;#x27;label&amp;#x27; style=&amp;#x27;&amp;#x27; transform=&amp;#x27;translate(-100%2c -36)&amp;#x27;%3e%3crect/%3e%3cforeignObject width=&amp;#x27;200&amp;#x27; height=&amp;#x27;72&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; style=&amp;#x27;display: table%3b white-space: break-spaces%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b width: 200px%3b&amp;#x27;%3e%3cspan class=&amp;#x27;nodeLabel&amp;#x27;%3e%3cp%3ecall external workflow to publish to reprepro hosted on Github Pages%3c/p%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3cg class=&amp;#x27;node default&amp;#x27; id=&amp;#x27;flowchart-i-19&amp;#x27; transform=&amp;#x27;translate(293%2c 663)&amp;#x27;%3e%3crect class=&amp;#x27;basic label-container&amp;#x27; style=&amp;#x27;&amp;#x27; x=&amp;#x27;-130&amp;#x27; y=&amp;#x27;-39&amp;#x27; width=&amp;#x27;260&amp;#x27; height=&amp;#x27;78&amp;#x27;/%3e%3cg class=&amp;#x27;label&amp;#x27; style=&amp;#x27;&amp;#x27; transform=&amp;#x27;translate(-100%2c -24)&amp;#x27;%3e%3crect/%3e%3cforeignObject width=&amp;#x27;200&amp;#x27; height=&amp;#x27;48&amp;#x27;%3e%3cdiv xmlns=&amp;#x27;http://www.w3.org/1999/xhtml&amp;#x27; style=&amp;#x27;display: table%3b white-space: break-spaces%3b line-height: 1.5%3b max-width: 200px%3b text-align: center%3b width: 200px%3b&amp;#x27;%3e%3cspan class=&amp;#x27;nodeLabel&amp;#x27;%3e%3cp%3esetup repo/conf for PPA%2c sign both .deb%2c and publish%3c/p%3e%3c/span%3e%3c/div%3e%3c/foreignObject%3e%3c/g%3e%3c/g%3e%3c/g%3e%3c/g%3e%3c/g%3e%3c/svg%3e&quot; width=&quot;586&quot;&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Great job getting this far! Packaging and publishing on Debian can seem very confusing because of the little amount of comprehensive documentation there is, but I hope that this guide can help to coalesce all of the available documentation into something practical and usable!&lt;/p&gt;
&lt;p&gt;I could have used off-the-shelf solutions for this, but I liked the process of understanding how to package and publish from scratch!&lt;/p&gt;
&lt;p&gt;These were some of the resources I had relied on when I was first starting out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.debian.org/Packaging/Intro&quot;&gt;Packaging/Intro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.debian.org/DebianRepository/SetupWithReprepro&quot;&gt;DebianRepository/SetupWithReprepro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://linsomniac.com/post/2025-03-18-building_and_publishing_apt_repos_to_github_pages/&quot;&gt;Building and Publishing Apt Repos to Github Pages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-use-reprepro-for-a-secure-package-repository-on-ubuntu-14-04&quot;&gt;How to Use Reprepro for a Secure Package Repository on Ubuntu 14.04&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.baeldung.com/linux/ppa&quot;&gt;Guide to Personal Package Archives&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;appendix-setting-up-a-debian-vm-on-macos-apple-silicon&quot;&gt;Appendix: Setting up a Debian VM on MacOS Apple Silicon&lt;/h2&gt;
&lt;p&gt;Thankfully, Debian has an ARM64 image for you to virtualize on MacOS Apple Silicon (which is what I used to experiment with packaging).&lt;/p&gt;
&lt;p&gt;The ISO isn’t immediately obvious because it’s not (to my knowledge) listed on the same page where you regularly download ISOs. Instead, you can find this image &lt;a href=&quot;https://cdimage.debian.org/debian-cd/current/arm64/iso-cd/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I used &lt;a href=&quot;https://www.virtualbox.org/&quot;&gt;VirtualBox&lt;/a&gt; because it’s very simple to get started. Create a VM and mount the ISO. I picked &lt;a href=&quot;https://www.xfce.org/&quot;&gt;XFCE&lt;/a&gt; as the &lt;a href=&quot;https://en.wikipedia.org/wiki/Desktop_environment&quot;&gt;desktop environment&lt;/a&gt; because I wanted to interactively download the releases from GitHub.&lt;/p&gt;
&lt;p&gt;You can then use this VM to test the commands and try to load the packaged application!&lt;/p&gt;
&lt;h2 id=&quot;appendix-packaging-workflow&quot;&gt;Appendix: Packaging workflow&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Build and release Git-Mastery CLI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  workflow_dispatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    tags&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;v*.*.*&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;permissions&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  contents&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;write&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  pull-requests&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;write&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  packages&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;read&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  issues&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;read&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  linux-build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    strategy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      matrix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        os&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ubuntu-24.04-arm&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    runs-on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ matrix.os }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Checkout source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Set up Python&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/setup-python@v5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          python-version&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;3.13&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Install dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          python -m pip install --upgrade pip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          pip install -r requirements.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Get binary name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        id&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;binary-name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          OS_VERSION&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ matrix.os }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          if [ $OS_VERSION = &quot;ubuntu-latest&quot; ]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            ARCHITECTURE=amd64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            ARCHITECTURE=arm64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          FILENAME=gitmastery-${GITHUB_REF_NAME#v}-linux-$ARCHITECTURE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;binary=$FILENAME&quot; &gt;&gt; $GITHUB_OUTPUT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Build binary&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          BINARY_NAME&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ steps.binary-name.outputs.binary }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;__version__ = \&quot;${GITHUB_REF_NAME}\&quot;&quot; &gt; app/version.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          pyinstaller --onefile main.py --name $BINARY_NAME&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Create GitHub Release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;softprops/action-gh-release@v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          files&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;dist/${{ steps.binary-name.outputs.binary }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          GITHUB_TOKEN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Publish package as artifact&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/upload-artifact@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ steps.binary-name.outputs.binary }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          path&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;dist/${{ steps.binary-name.outputs.binary }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  debian-build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # We support both ARM64 and AMD64 since Debian comes with support for&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # these two out of the box&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    needs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;linux-build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    strategy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      matrix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        os&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ubuntu-24.04-arm&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    runs-on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ matrix.os }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Checkout source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          path&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;app&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Extract variables&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          ARCHITECTURE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ matrix.architecture }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          OS_VERSION&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ matrix.os }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          if [ $OS_VERSION = &quot;ubuntu-latest&quot; ]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            ARCHITECTURE=amd64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            ARCHITECTURE=arm64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;VERSION=${GITHUB_REF_NAME#v}&quot; &gt;&gt; $GITHUB_ENV&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;ARCHITECTURE=${ARCHITECTURE}&quot; &gt;&gt; $GITHUB_ENV&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Get the tag&apos;s commit message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          cd app/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          CHANGELOG_MESSAGE=$(git show ${GITHUB_REF_NAME} --no-patch --pretty=format:%s)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;CHANGELOG_MESSAGE=${CHANGELOG_MESSAGE}&quot; &gt;&gt; $GITHUB_ENV&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Install Debian packaging tools&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          sudo apt-get install devscripts build-essential debhelper-compat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Create folder structure for ${{ env.ARCHITECTURE }} distribution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          mkdir gitmastery-${VERSION}-${ARCHITECTURE}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Download ${{ env.ARCHITECTURE }} binaries from artifacts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;actions/download-artifact@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;gitmastery-${{ env.VERSION }}-linux-${{ env.ARCHITECTURE }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          path&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;gitmastery-${{ env.VERSION }}-${{ env.ARCHITECTURE }}/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Create upstream tarball .orig.tar.gz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Create .orig.tar.gz file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          tar -czf gitmastery_${VERSION}.orig.tar.gz gitmastery-${VERSION}-${ARCHITECTURE}/gitmastery-${VERSION}-linux-${ARCHITECTURE}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Generate Debian packaging files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        working-directory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;gitmastery-${{ env.VERSION }}-${{ env.ARCHITECTURE }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        # TODO: Update to something agnostic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          EMAIL&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;woojiahao1234@gmail.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          NAME&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Jiahao, Woo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          file gitmastery-${VERSION}-linux-${ARCHITECTURE}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Create the debian folder&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          mkdir debian&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Generate the changelog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # TODO: Maybe detect if major version change, then make it urgent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          dch --create -v ${VERSION}-1 -u low --package gitmastery &quot;$CHANGELOG_MESSAGE&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Create the control file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # TODO: Maybe detect if major version change, then make it mandatory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;&quot;&quot;Source: gitmastery&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Maintainer: $NAME &amp;#x3C;$EMAIL&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Section: misc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Priority: optional&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Standards-Version: 4.7.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Build-Depends: debhelper-compat (= 13)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Package: gitmastery&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Architecture: ${ARCHITECTURE}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Depends: ${shlibs:Depends}, ${misc:Depends}, libc6 (&gt;= 2.35), python3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          Description: execute Git-Mastery&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            gitmastery is a Git learning tool built by the National University of Singapore School of Computing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;&quot;&quot; &gt; debian/control&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Copy over the MIT license from the main app to this release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          cat ../app/LICENSE &gt; debian/copyright&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          mkdir debian/source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;3.0 (quilt)&quot; &gt; debian/source/format&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Provide the rules for installation, using -e to preserve the tab character as per:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # https://wiki.debian.org/Packaging/Intro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # $(DESTDIR) resolves to debian/binarypackage/ as seen in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # https://www.debian.org/doc/manuals/debmake-doc/ch06.en.html#ftn.idp1797&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo -e $&quot;&quot;&quot;#!/usr/bin/make -f&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          %:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          \tdh \$@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          \n&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          override_dh_auto_install:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          \tinstall -D -m 0755 gitmastery-${VERSION}-linux-${ARCHITECTURE} debian/gitmastery/usr/bin/gitmastery&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;&quot;&quot; &gt; debian/rules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;&quot;&quot;usr/bin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;&quot;&quot; &gt; debian/gitmastery.dirs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          mkdir -p debian/source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          echo &quot;&quot;&quot;gitmastery-${VERSION}-linux-${ARCHITECTURE}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;&quot;&quot; &gt; debian/source/include-binaries&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          cat debian/rules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          # Build the package&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          dpkg-buildpackage -us -uc -a ${ARCHITECTURE}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Create GitHub Release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;softprops/action-gh-release@v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          files&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;gitmastery_${{ env.VERSION }}-1_${{ env.ARCHITECTURE }}.deb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;          GITHUB_TOKEN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  debian-publish-apt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    needs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;debian-build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    permissions&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;write-all&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    uses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;git-mastery/gitmastery-apt-repo/.github/workflows/debian-apt-repo.yml@main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      version&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${{ github.ref_name }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    secrets&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;inherit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description><pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate></item><item><title>Unpacking Options in Python</title><link>https://blog.woojiahao.com/post/unpacking-options-in-python</link><guid isPermaLink="true">https://blog.woojiahao.com/post/unpacking-options-in-python</guid><description>&lt;p&gt;I have been working on pretty interesting problems as part of
&lt;a href=&quot;https://github.com/git-mastery&quot;&gt;Git-Mastery&lt;/a&gt; (we are looking for open-source
contributors!) and one of the most interesting problems I have encountered
recently is having to design a wrapper around the Git CLI.&lt;/p&gt;
&lt;p&gt;A Git command (or any CLI in general) can comprise of arguments, options, and
flags.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [-a &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; --interactive&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; --patch]&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [-s] [-v] [-u[&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;mode&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]] [--amend]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	   [--dry-run] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;commit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; --fixup&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [(amend&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reword&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&gt;&amp;#x3C;commit&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;	   [-F &amp;#x3C;file&gt; | -m &amp;#x3C;msg&gt;] [--reset-author] [--allow-empty]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;	   [--allow-empty-message] [--no-verify] [-e] [--author=&amp;#x3C;author&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;	   [--date=&amp;#x3C;date&gt;] [--cleanup=&amp;#x3C;mode&gt;] [--[no-]status]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;	   [-i | -o] [--pathspec-from-file=&amp;#x3C;file&gt; [--pathspec-file-nul]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;	   [(--trailer &amp;#x3C;token&gt;[(=|:)&amp;#x3C;value&gt;])…​] [-S[&amp;#x3C;keyid&gt;]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;	   [--] [&amp;#x3C;pathspec&gt;…​]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;How do we exactly model so much information within a single function?&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git.commit()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Arguments will become parameters:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    self,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    pathspec: Optional[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; None&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But because the order of the flags and options can vary, it does not make sense
to expand every single one of them into a separate parameter (because it’s not
very sustainable to maintain it in my opinion).&lt;/p&gt;
&lt;p&gt;Instead, we represent the flags and options as a &lt;code&gt;TypedDict&lt;/code&gt;
(&lt;a href=&quot;https://docs.python.org/3/library/typing.html#typing.TypedDict&quot;&gt;docs&lt;/a&gt;) instead:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CommitOptions&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TypedDict&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;total&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;False&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    all&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    reuse_message: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    message: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    allow_empty: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    no_edit: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we can use &lt;code&gt;Unpack&lt;/code&gt;
(&lt;a href=&quot;https://docs.python.org/3/library/typing.html#typing.Unpack&quot;&gt;docs&lt;/a&gt;) to expand
these parameters while providing type hints for the fields of the &lt;code&gt;TypedDict&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    self,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    pathspec: Optional[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; None&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    **&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;options: Unpack[CommitOptions],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works in tandem with &lt;code&gt;**&lt;/code&gt; to expand these into the respective fields.&lt;/p&gt;
&lt;p&gt;When we call this function, we will see that the type hints include every field
along with its associated type:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/unpacking-options-in-python/type-hint.png&quot; alt=&quot;Type hint&quot;&gt;&lt;/p&gt;
&lt;p&gt;Then, to access the fields, you can use &lt;code&gt;options.get()&lt;/code&gt; (since we have specified
&lt;code&gt;total=False&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The result is a function that we can call with any order of parameters without
exploding our function signature at once:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;git.commit(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;dest&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;  message&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Add dest/&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;  no_edit&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;  allow_empty&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works especially well when you have a much larger number of flags and
options:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RestoreOptions&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TypedDict&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;total&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;False&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    source: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    worktree: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    staged: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ours: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    theirs: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    merge: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    conflict: Union[Literal[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;merge&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], Literal[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;diff3&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], Literal[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;zdiff3&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ignore_unmerged: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ignore_skip_worktree_bits: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    recurse_submodules: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    no_recurse_submodules: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    overlay: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    no_overlay: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are interested in how we have used this pattern in Git-Mastery, feel free
to refer to the &lt;code&gt;repo-smith&lt;/code&gt; repository: &lt;a href=&quot;https://github.com/git-mastery/repo-smith&quot;&gt;https://github.com/git-mastery/repo-smith&lt;/a&gt;&lt;/p&gt;</description><pubDate>Sat, 27 Dec 2025 00:00:00 GMT</pubDate></item><item><title>Building Components for Markdown in Astro</title><link>https://blog.woojiahao.com/post/building-components-for-markdown</link><guid isPermaLink="true">https://blog.woojiahao.com/post/building-components-for-markdown</guid><description>&lt;p&gt;MDX allows you to use JSX in Markdown, embedding these components within the content, adding more flexibility in the type of content Markdown can generate.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mdx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;import {Chart} from &apos;./snowfall.js&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;export const year = 2023&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF;font-weight:bold&quot;&gt;# Last year’s snowfall&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;In {year}, the snowfall was above average.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;It was followed by a warm spring which caused&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flood conditions in many of the nearby rivers.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;Chart color=&quot;#fcb32c&quot; year={year} /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, I use Neovim, and Neovim has a shocking lack of &lt;a href=&quot;https://phelipetls.github.io/posts/mdx-syntax-highlight-treesitter-nvim/&quot;&gt;&lt;em&gt;good&lt;/em&gt; support for MDX files&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After trying to replicate Hugo’s shortcodes in Markdown and spending a bunch of time trying to get MDX to work nicely with Neovim for &lt;a href=&quot;https://git-mastery.github.io/learning-lab&quot;&gt;@git-mastery&lt;/a&gt;, I decided to look into how I could do it purely in Markdown.&lt;/p&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://gohugo.io/content-management/shortcodes/&quot;&gt;Shortcodes&lt;/a&gt; in Hugo are custom templates that you could embed in your markdown files:&lt;/p&gt;&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;md&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{&amp;#x3C; gist user 23932424365401ffa5e9d9810102a477 &gt;}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;problem&quot;&gt;Problem&lt;/h2&gt;
&lt;p&gt;As part of @git-mastery’s setup guide, I wanted to collapse information into tabs, such as having different OS instructions. I wanted users’ preferences to be persisted into &lt;code&gt;localStorage&lt;/code&gt;, and shared across all other tabs with the same “key”. However, without MDX, this was not easy to create.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/building-components-in-markdown/end-goal.gif&quot; alt=&quot;End goal&quot;&gt;&lt;/p&gt;
&lt;p&gt;Additionally, the syntax to create these tabs should be as minimal as possible, so that authors of these files do not need to write extra convoluted Markdown.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;md&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::::tabs{key=&quot;bash_installation&quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:::tab{value=&quot;windows&quot; header=&quot;Windows&quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;If you are using Windows, you should try the following:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:::&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:::tab{value=&quot;unix&quot; header=&quot;Linux/MacOS&quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;If you are using Linux or MacOS, you should try the following:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:::&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::::&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::::tabs{key=&quot;bash_installation&quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:::tab{value=&quot;windows&quot; header=&quot;Another windows&quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;If you are using Windows, you should try the following:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:::&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:::tab{value=&quot;unix&quot; header=&quot;Another Linux/MacOS&quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;If you are using Linux or MacOS, you should try the following:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:::&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::::&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;markdown-processing&quot;&gt;Markdown processing&lt;/h2&gt;
&lt;p&gt;Before diving into the implementation details, let me briefly cover the high-level of how Astro processes Markdown files and generates the resulting HTML pages.&lt;/p&gt;
&lt;img src=&quot;/building-components-in-markdown/markdown-processing.jpg&quot; style=&quot;max-width: 250px; width: 60%;&quot;&gt;
&lt;p&gt;Astro uses &lt;code&gt;remark&lt;/code&gt;, &lt;code&gt;remark-rehype&lt;/code&gt;, and &lt;code&gt;rehype&lt;/code&gt; to process Markdown files, converting them into HTML files that are rendered (like this page!).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/remarkjs/remark&quot;&gt;&lt;code&gt;remark&lt;/code&gt;&lt;/a&gt;: processes Markdown files as &lt;code&gt;mdast&lt;/code&gt; or Markdown Abstract Syntax Tree (AST)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rehypejs/rehype&quot;&gt;&lt;code&gt;rehype&lt;/code&gt;&lt;/a&gt;: processes HTML files as &lt;code&gt;hast&lt;/code&gt; or HTML AST&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/remark-rehype&quot;&gt;&lt;code&gt;remark-rehype&lt;/code&gt;&lt;/a&gt;: transforms &lt;code&gt;mdast&lt;/code&gt; into &lt;code&gt;hast&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To build the tabs system, we essentially have to “modify” the final HTML that we generate, so the syntax used above is correctly transformed into the necessary components.&lt;/p&gt;
&lt;h2 id=&quot;using-directives&quot;&gt;Using directives&lt;/h2&gt;
&lt;p&gt;To achieve shortcode-like syntax, we can use &lt;a href=&quot;https://github.com/remarkjs/remark-directive&quot;&gt;&lt;code&gt;remark-directive&lt;/code&gt;&lt;/a&gt;, an extension on top of &lt;code&gt;remark&lt;/code&gt; that allows &lt;code&gt;:::container&lt;/code&gt; to be parsed as a custom component in &lt;code&gt;remark&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So,&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;md&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:::tabs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:::&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Would be recognized as creating a “container directive” with name &lt;code&gt;tabs&lt;/code&gt; which we can identify in the &lt;code&gt;mdast&lt;/code&gt; generated.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;remark-directive&lt;/code&gt; also supports parent-child nesting:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;md&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::::tabs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:::tab&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&amp;#x3C;!-- tab is a child component to tabs --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:::&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::::&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Directives are declared via &lt;code&gt;:::name[label]{attributes}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For this use case, we only care about the &lt;code&gt;attributes&lt;/code&gt;, which have the following syntax:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;{a=b}&lt;/code&gt; or &lt;code&gt;{a=&quot;b&quot;}&lt;/code&gt;: creates an attribute &lt;code&gt;a&lt;/code&gt; with value &lt;code&gt;&quot;b&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{a=&quot;b&quot; c=&quot;d&quot;}&lt;/code&gt;: creates two attributes &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{.big .red}&lt;/code&gt;: creates the &lt;code&gt;class&lt;/code&gt; attribute where the class is &lt;code&gt;&quot;big red&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{#big}&lt;/code&gt;: creates the &lt;code&gt;id&lt;/code&gt; attribute where the id is &lt;code&gt;&quot;big&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We use these attributes to provide the following properties for our tabs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;tabs{key=&quot;&quot;}&lt;/code&gt;: global &lt;code&gt;key&lt;/code&gt; of &lt;code&gt;tabs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tab{value=&quot;&quot;}&lt;/code&gt;: &lt;code&gt;value&lt;/code&gt; associated with the parent &lt;code&gt;tabs&lt;/code&gt;’s &lt;code&gt;key&lt;/code&gt;; persisted into &lt;code&gt;localStorage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tab{header=&quot;&quot;}&lt;/code&gt;: &lt;code&gt;header&lt;/code&gt; to render at the top of the tabs&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;setting-up-remark-directive&quot;&gt;Setting up &lt;code&gt;remark-directive&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;To setup &lt;code&gt;remark-directive&lt;/code&gt; in Astro, download the package:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;yarn&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; remark-directive&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, update &lt;code&gt;astro.config.mjs&lt;/code&gt; to include it:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; remarkDirective &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;remark-directive&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; defineConfig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  vite: { &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    //... &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  markdown: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    remarkPlugins: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      remarkDirective,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, Astro knows to run this &lt;code&gt;remarkDirective&lt;/code&gt; remark plugin.&lt;/p&gt;
&lt;h2 id=&quot;plugins&quot;&gt;Plugins&lt;/h2&gt;
&lt;p&gt;Notice that &lt;code&gt;remark&lt;/code&gt; and &lt;code&gt;rehype&lt;/code&gt; aren’t just single one-off extensions, but rather, a suite of plugins that incrementally and sequentially modify the &lt;code&gt;mdast&lt;/code&gt; and &lt;code&gt;hast&lt;/code&gt; respectively:&lt;/p&gt;
&lt;img src=&quot;/building-components-in-markdown/remark-rehype-plugins.jpg&quot; style=&quot;max-width: 400px; width: 80%;&quot;&gt;
&lt;p&gt;As such, we can build our own plugins to implement custom transformations on top of the original &lt;code&gt;mdast&lt;/code&gt; and &lt;code&gt;hast&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;creating-a-remark-plugin&quot;&gt;Creating a &lt;code&gt;remark&lt;/code&gt; plugin&lt;/h2&gt;
&lt;p&gt;Now that we have access to directives, we can build a custom plugin that will transform the &lt;code&gt;tabs&lt;/code&gt; directives into the necessary elements.&lt;/p&gt;
&lt;h3 id=&quot;remark-plugin-skeleton&quot;&gt;&lt;code&gt;remark&lt;/code&gt; plugin skeleton&lt;/h3&gt;
&lt;p&gt;First, install the necessary dependency to write a plugin:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;yarn&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; mdast&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; unified&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; unist-util-visit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, create a new plugin &lt;code&gt;src/plugins/remark-tabs.ts&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { Root } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;mdast&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { Plugin } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;unified&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { visit } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;unist-util-visit&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; remarkTabs&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Plugin&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;[], &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Root&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;tree&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    visit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(tree, (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;index&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; number&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;parent&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; remarkTabs;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;remark&lt;/code&gt; plugin, denoted by the type &lt;code&gt;Plugin&amp;#x3C;[], Root&gt;&lt;/code&gt;, is a function that visits the &lt;code&gt;mdast&lt;/code&gt;, modifying the node or the node’s parent during traversal (using the &lt;a href=&quot;https://refactoring.guru/design-patterns/visitor&quot;&gt;visitor pattern&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Our plugin’s &lt;code&gt;mdast&lt;/code&gt; transformation will be written within the &lt;code&gt;visit&lt;/code&gt; function callback.&lt;/p&gt;
&lt;h3 id=&quot;detecting-directives&quot;&gt;Detecting directives&lt;/h3&gt;
&lt;p&gt;There are several types of directives, but we are only interested in the &lt;code&gt;containerDirective&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (node.type &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;containerDirective&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; node.name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;tabs&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; tabs&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; node.children.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;child&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      child.type &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;containerDirective&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; child.name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;tab&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The plugin only executes the transformation when the current &lt;code&gt;node&lt;/code&gt; is a container directive and when the node’s name is &lt;code&gt;tabs&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;creating-wrapper-elements&quot;&gt;Creating wrapper elements&lt;/h3&gt;
&lt;p&gt;Normally, directives are not used in &lt;code&gt;remark&lt;/code&gt;, so they will not be converted to a meaningful HTML element. But, we can change that by modifying the &lt;code&gt;hName&lt;/code&gt; of a node:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;node.data &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  hName: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;div&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  hProperties: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    className: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;tabs&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can even modify the &lt;code&gt;hProperties&lt;/code&gt; to include a &lt;code&gt;className&lt;/code&gt; for the &lt;code&gt;div&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But, what we want is not just a container for tabs. We want a header for the tabs and a container for the content of each tab.&lt;/p&gt;
&lt;p&gt;So instead, we need to generate a wrapper element, which “replaces” the current &lt;code&gt;mdast&lt;/code&gt; of the &lt;code&gt;tabs&lt;/code&gt; container directive with a new AST element that contains all of the necessary components:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; wrapper&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  type: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;element&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  data: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    hName: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;div&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    hProperties: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      className: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;tabs&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      &quot;data-tabs-key&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: node.attributes?.[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  children: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      type: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;element&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      data: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        hName: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;div&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        hProperties: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          className: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;selector&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      children: tabs.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;tab&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        type: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;element&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        data: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          hName: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;div&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          hProperties: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            &quot;data-tab-selector-value&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: tab.attributes.value,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        children: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            type: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            value: tab.attributes.header,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      })),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tabs.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;tab&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      tab.data &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        hProperties &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          &quot;data-tab-value&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: tab.attributes.value &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;The specifics of &lt;code&gt;mdast&lt;/code&gt; syntax can be found &lt;a href=&quot;https://github.com/syntax-tree/mdast&quot;&gt;in the Github repository&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;There is a ton going on, but essentially, we are converting the initially naive &lt;code&gt;tabs&lt;/code&gt; container directive into one with the header, selectors, and tab content.&lt;/p&gt;
&lt;img src=&quot;/building-components-in-markdown/remark-plugin.jpg&quot; style=&quot;max-width: 500px; width: 90%;&quot;&gt;
&lt;p&gt;Along with these transformations, we are attaching additional properties (through &lt;code&gt;hProperties&lt;/code&gt;) to each component, such as &lt;code&gt;data-tabs-key&lt;/code&gt; to be the &lt;code&gt;key&lt;/code&gt; attribute of the &lt;code&gt;tabs&lt;/code&gt; container directive.&lt;/p&gt;
&lt;p&gt;The final step is to set the current node’s parent to this new wrapper element, effectively replacing the current node with this new wrapper:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;parent.children[index] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; wrapper&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;using-the-plugin&quot;&gt;Using the plugin&lt;/h3&gt;
&lt;p&gt;To use the plugin we just created, update &lt;code&gt;astro.config.mjs&lt;/code&gt; again, adding the &lt;code&gt;remarkTabs&lt;/code&gt; plugin AFTER the &lt;code&gt;remarkDirective&lt;/code&gt; plugin.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Recall that plugins run sequentially, so if we used &lt;code&gt;remarkTabs&lt;/code&gt; before &lt;code&gt;remarkDirective&lt;/code&gt;, we would not have access to the &lt;code&gt;containerDirective&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; remarkTabs &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;./src/plugins/remark-tabs&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; defineConfig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  markdown: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    remarkPlugins: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      remarkDirective,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      remarkTabs,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you can verify that the modified &lt;code&gt;mdast&lt;/code&gt; changes are reflected by rendering a tabs component and verifying the HTML:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;tabs&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; data-tabs-key&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;bash_installation&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;selector&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; data-tab-selector-value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;windows&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;Windows&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; data-tab-selector-value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;unix&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;Linux/MacOS&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; data-tab-value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;windows&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;If you are using Windows, you should try the following:&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; data-tab-value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;unix&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;If you are using Linux or MacOS, you should try the following:&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great! But we are missing the critical interactivity of selecting tabs and persisting the choices.&lt;/p&gt;
&lt;h2 id=&quot;creating-a-rehype-plugin&quot;&gt;Creating a &lt;code&gt;rehype&lt;/code&gt; plugin&lt;/h2&gt;
&lt;p&gt;Not everything can be embedded within the &lt;code&gt;remark&lt;/code&gt; plugin. So, we have to modify the &lt;code&gt;hast&lt;/code&gt; generated as well, adding the necessary interactivity for the tabs.&lt;/p&gt;
&lt;h3 id=&quot;rehype-plugin-skeleton&quot;&gt;&lt;code&gt;rehype&lt;/code&gt; plugin skeleton&lt;/h3&gt;
&lt;p&gt;Just like the &lt;code&gt;remark&lt;/code&gt; plugin, &lt;code&gt;rehype&lt;/code&gt; plugins are defined as functions with the visitor pattern.&lt;/p&gt;
&lt;p&gt;First, install the necessary dependency (the others were already installed previously):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;yarn&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; hast&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, create the plugin &lt;code&gt;src/plugins/rehype-tabs.ts&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { visit } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;unist-util-visit&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { Plugin } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;unified&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { Root } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;hast&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; rehypeTabs&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Plugin&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;[], &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Root&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;tree&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    visit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(tree, (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; rehypeTabs;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time, we are visiting the &lt;code&gt;hast&lt;/code&gt;, so we can think of each node as a HTML element.&lt;/p&gt;
&lt;h3 id=&quot;detecting-elements&quot;&gt;Detecting elements&lt;/h3&gt;
&lt;p&gt;Again, like the &lt;code&gt;remark&lt;/code&gt; plugin, we will need to detect when we are visiting the various &lt;code&gt;tabs&lt;/code&gt; elements created earlier.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (node.type &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;element&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; node.tagName &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;div&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; classNames&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; node.properties?.className?.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;split&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (classNames.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;includes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;tabs&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;data-tab-selector-value&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; node.properties) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each &lt;code&gt;node&lt;/code&gt; has a &lt;code&gt;type&lt;/code&gt; and &lt;code&gt;tagName&lt;/code&gt; which we use as the preliminary filters. Then, we can check if the &lt;code&gt;class&lt;/code&gt; HTML attribute contains &lt;code&gt;tabs&lt;/code&gt; to know that we are visiting the &lt;code&gt;tabs&lt;/code&gt; container, or if the node’s &lt;code&gt;properties&lt;/code&gt; contains the &lt;code&gt;data-tab-selector-value&lt;/code&gt; property, which we added to the selectors.&lt;/p&gt;
&lt;h3 id=&quot;storing-tab-keys-on-load&quot;&gt;Storing tab keys on load&lt;/h3&gt;
&lt;p&gt;When we first load the &lt;code&gt;tabs&lt;/code&gt; element, we want to ensure that our &lt;code&gt;localStorage&lt;/code&gt; contains the global &lt;code&gt;key&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To do so, we can append a &lt;code&gt;&amp;#x3C;script&gt;&lt;/code&gt; element to the end of the &lt;code&gt;hast&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; tabsKey&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; node.properties[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;data-tabs-key&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; availableKeys&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; JSON&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(node.properties[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;data-tabs&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; firstKey&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; availableKeys[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; localStorageTabsKey&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; `tabs-${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tabsKey&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tree.children.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // @ts-ignore&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  type: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;element&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  tagName: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;script&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  properties: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  children: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      type: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      value: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      (() =&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        if (localStorage.getItem(&quot;${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;localStorageTabsKey&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&quot;) == null) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          localStorage.setItem(&quot;${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;localStorageTabsKey&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&quot;, ${&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;JSON&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stringify&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;firstKey&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      })()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      `&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;The specifics of &lt;code&gt;hast&lt;/code&gt; syntax can be found &lt;a href=&quot;https://github.com/syntax-tree/hast&quot;&gt;in the Github repository&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;This is the key to embedding interactivity in Markdown components. It’s not very fancy, but it certainly gets the job done.&lt;/p&gt;
&lt;p&gt;The script above will execute when the page loads and store the key &lt;code&gt;tabs-X&lt;/code&gt; into &lt;code&gt;localStorage&lt;/code&gt;. The &lt;code&gt;key&lt;/code&gt; is specified by the author of the Markdown file.&lt;/p&gt;
&lt;h3 id=&quot;loading-and-updating-selection&quot;&gt;Loading and updating selection&lt;/h3&gt;
&lt;p&gt;Then, we need to incorporate the user’s selection of tabs, ensuring that their selection:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Propagates to all other tabs that share the same &lt;code&gt;tabs&lt;/code&gt; &lt;code&gt;key&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Updates the &lt;code&gt;localStorage&lt;/code&gt; value associated with &lt;code&gt;tabs-X&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Switches the visible tab to their selection&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; tabValue&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; node.properties[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;data-tab-selector-value&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; tabsKey&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; node.properties[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;data-tabs-key&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; localStorageTabsKey&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; `tabs-${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tabsKey&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tree.children.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // @ts-ignore&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  type: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;element&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  tagName: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;script&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  properties: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  children: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      type: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      value: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      (() =&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          const selectorTabsAcross = document.querySelectorAll(&quot;div.tabs[data-tabs-key=&apos;${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tabsKey&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&apos;] &gt; div.selector &gt; div[data-tab-selector-value=&apos;${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tabValue&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&apos;]&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          const tabs = document.querySelectorAll(&quot;div.tabs[data-tabs-key=&apos;${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tabsKey&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&apos;] &gt; div.tabs-content &gt; div.tab&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          const selectorTabs = document.querySelectorAll(&quot;div.tabs[data-tabs-key=&apos;${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tabsKey&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&apos;] &gt; div.selector &gt; div[data-tab-selector-value]&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          const value = localStorage.getItem(&quot;${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;localStorageTabsKey&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          select(value)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          function select(value) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;              for (const tab of tabs) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  if (tab.attributes[&quot;data-tab-value&quot;].nodeValue !== value) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                      tab.classList.remove(&quot;active&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  } else {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                      tab.classList.add(&quot;active&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;              }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;              for (const selectorTab of selectorTabs) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  if (selectorTab.attributes[&quot;data-tab-selector-value&quot;].nodeValue !== value) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                      selectorTab.classList.remove(&quot;active-selector&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  } else {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                      selectorTab.classList.add(&quot;active-selector&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;              }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          for (const t of selectorTabsAcross) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;              t.addEventListener(&quot;click&quot;, function() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  select(&quot;${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tabValue&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  localStorage.setItem(&quot;${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;localStorageTabsKey&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&quot;, ${&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;JSON&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stringify&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tabValue&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;              })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      })()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      `&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Essentially, we are selecting the necessary elements, loading the initial state, and specifying the &lt;code&gt;click&lt;/code&gt; event listeners. When a user selects a tab, it will add the &lt;code&gt;active&lt;/code&gt; class to the &lt;code&gt;tab&lt;/code&gt; element and the &lt;code&gt;active-selector&lt;/code&gt; class to the selector tab, along with updating the &lt;code&gt;localStorage&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;loading-the-plugin&quot;&gt;Loading the plugin&lt;/h3&gt;
&lt;p&gt;Like the &lt;code&gt;remark&lt;/code&gt; plugin, we need to update &lt;code&gt;astro.config.mjs&lt;/code&gt; to use it by adding the &lt;code&gt;rehypeTabs&lt;/code&gt; plugin.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; remarkTabs &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;./src/plugins/remark-tabs&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; rehypeTabs &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;./src/plugins/rehype-tabs&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; defineConfig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  markdown: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    remarkPlugins: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      remarkDirective,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      remarkTabs,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    rehypePlugins: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      rehypeTabs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you can verify that scripts were added to the end of the &lt;code&gt;hast&lt;/code&gt; of the parent container:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/building-components-in-markdown/scripts.png&quot; alt=&quot;Scripts&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;styling-the-component&quot;&gt;Styling the component&lt;/h2&gt;
&lt;p&gt;We are almost done with creating our component. We just need to make sure that the component is styled correctly. The most important part is ensuring that only the &lt;code&gt;active&lt;/code&gt; tab is shown.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.tabs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; mb-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;4;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.tabs&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; .selector&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; flex&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; flex-row&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.tabs&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; .selector&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt; div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;data-tab-selector-key&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; inline-block&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; px-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;4 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;py-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;2 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;border-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;1 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;border-neutral-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;300 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;border-b-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;0 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;hover&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:cursor-pointer;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.tabs&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; .selector&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt; div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;data-tab-selector-key&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;:first-child&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; rounded-tl-md&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.tabs&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; .selector&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt; div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;data-tab-selector-key&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;:last-child&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; rounded-tr-md&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.tabs&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; .selector&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt; div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;data-tab-selector-key&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;:not&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;:first-child&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; border-l-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;0;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.tabs&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; .tabs-content&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; w-full&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; p-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;4 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;border-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;1 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;border-neutral-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;300 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;rounded-b-md&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.tabs&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt; div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.selector&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt; div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;data-tab-selector-key&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;:not&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.active-selector&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; bg-neutral-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;50 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;text-gray-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;500;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.tabs&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt; div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.tab:not&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.active&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; hidden&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.tabs&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt; div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;.tab.active&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; block&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I use &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;Tailwind&lt;/a&gt; to style the tabs, but you can use whatever you want.
Make sure you import this style into whichever component renders your Markdown files.&lt;/p&gt;
&lt;p&gt;Voila! You now have a fully functioning tab system with persistent storage!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/building-components-in-markdown/end-goal.gif&quot; alt=&quot;End goal&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;closing&quot;&gt;Closing&lt;/h2&gt;
&lt;p&gt;Yes, I built this out of spite due to the lack of good MDX support in Neovim. Yes, it might not be the most intuitive thing. Yes, MDX could have done this with much less effort.&lt;/p&gt;
&lt;p&gt;But this was a fun dive into Markdown and HTML ASTs with &lt;code&gt;remark&lt;/code&gt; and &lt;code&gt;rehype&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you are interested, I have written other Markdown components for @git-mastery &lt;a href=&quot;https://github.com/git-mastery/learning-lab/tree/main/src/plugins&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Tue, 29 Apr 2025 00:00:00 GMT</pubDate></item><item><title>Understanding Systems with Sequence Diagrams</title><link>https://blog.woojiahao.com/post/understanding-systems-with-sequence-diagrams</link><guid isPermaLink="true">https://blog.woojiahao.com/post/understanding-systems-with-sequence-diagrams</guid><description>&lt;p&gt;Uncle Bob (Robert C. Martin) wrote in &lt;a href=&quot;https://www.amazon.sg/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882&quot;&gt;Clean Code&lt;/a&gt; that “the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code…”&lt;/p&gt;
&lt;p&gt;As software engineers, reading code is our bread and butter. Maintaining a legacy system? You have to read the legacy code. Want to build a website? You’re reading framework and library documentations. Contributing to a project? You are combing through existing code to figure out how everything works before contributing meaningfully. Writing a Request For Comments (RFC)? Guess what? You have to read the old code to propose changes to it.&lt;/p&gt;
&lt;p&gt;It is an immutable part of software engineering, yet after talking to various engineers, I have come to realize that there is no well-defined system to understand and navigate complex codebases.&lt;/p&gt;
&lt;p&gt;So today, I will try to introduce a system I have used throughout the years to understand large systems and start contributing to them within hours: &lt;strong&gt;sequence diagrams&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;practical-sequence-diagrams&quot;&gt;Practical sequence diagrams&lt;/h2&gt;
&lt;p&gt;You might remember sequence diagrams from a software engineering class you took where your takeaway was that UML diagrams like sequence diagrams are fraught with rigid rules and terminology. [1]&lt;/p&gt;
&lt;p&gt;However, my approach to sequence diagrams focuses on its practical applications, and adapting it to work within a more “realistic” software engineering environment.&lt;/p&gt;
&lt;p&gt;I believe that sequence diagrams should be used to understand how software components interact with each other. So, it is less important that you remember what a lifeline is or ensure that class names are underlined, but rather, focus on using sequence diagrams as a visual tool on top of note-taking.&lt;/p&gt;
&lt;p&gt;In fact, my flow for tracing codebases using sequence diagrams is very simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open Notion or VS Code&lt;/li&gt;
&lt;li&gt;Create a new page or Markdown file&lt;/li&gt;
&lt;li&gt;Create a codeblock for Mermaid&lt;/li&gt;
&lt;li&gt;Find an entry point for the code you are interested in&lt;/li&gt;
&lt;li&gt;Trace the code by jumping through definitions and following each line&lt;/li&gt;
&lt;li&gt;Add the important details into the sequence diagram&lt;/li&gt;
&lt;li&gt;In the rest of the document, add any additional details to supplement the diagram&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Before I explain what is considered “important details” for the sequence diagram or how to construct the sequence diagrams, I will first cover the basics of Mermaid, the tool I use to generate sequence diagrams using code.&lt;/p&gt;
&lt;h2 id=&quot;mermaid-crash-course&quot;&gt;Mermaid crash course&lt;/h2&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;I will only cover the very bare minimum you need to create sequence diagrams. These are all the notations I use 99% of the time.&lt;/p&gt;&lt;p&gt;If you are interested in learning more, feel free to refer to the &lt;a href=&quot;https://mermaid.js.org/syntax/sequenceDiagram.html&quot;&gt;official documentation&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;To start with creating a sequence diagram in Mermaid, you need to declare the diagram type:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you can declare actors via &lt;code&gt;actor &amp;#x3C;name&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  actor User&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This generates a stick figure you can use to represent users:&lt;/p&gt;
&lt;img alt=&quot;&quot; height=&quot;171&quot; id=&quot;mermaid-0&quot; src=&quot;data:image/svg+xml,%3csvg id=&amp;#x27;mermaid-0&amp;#x27; width=&amp;#x27;100%25&amp;#x27; xmlns=&amp;#x27;http://www.w3.org/2000/svg&amp;#x27; xmlns:xlink=&amp;#x27;http://www.w3.org/1999/xlink&amp;#x27; style=&amp;#x27;max-width: 250px%3b&amp;#x27; viewBox=&amp;#x27;-50 -10 250 171&amp;#x27; role=&amp;#x27;graphics-document document&amp;#x27; aria-roledescription=&amp;#x27;sequence&amp;#x27;%3e%3cg/%3e%3cg%3e%3cline id=&amp;#x27;actor0&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;80&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;85&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;User&amp;#x27;/%3e%3c/g%3e%3cstyle%3e%23mermaid-0%7bfont-family:arial%2csans-serif%3bfont-size:16px%3bfill:%23333%3b%7d%40keyframes edge-animation-frame%7bfrom%7bstroke-dashoffset:0%3b%7d%7d%40keyframes dash%7bto%7bstroke-dashoffset:0%3b%7d%7d%23mermaid-0 .edge-animation-slow%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 50s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-0 .edge-animation-fast%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 20s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-0 .error-icon%7bfill:%23552222%3b%7d%23mermaid-0 .error-text%7bfill:%23552222%3bstroke:%23552222%3b%7d%23mermaid-0 .edge-thickness-normal%7bstroke-width:1px%3b%7d%23mermaid-0 .edge-thickness-thick%7bstroke-width:3.5px%3b%7d%23mermaid-0 .edge-pattern-solid%7bstroke-dasharray:0%3b%7d%23mermaid-0 .edge-thickness-invisible%7bstroke-width:0%3bfill:none%3b%7d%23mermaid-0 .edge-pattern-dashed%7bstroke-dasharray:3%3b%7d%23mermaid-0 .edge-pattern-dotted%7bstroke-dasharray:2%3b%7d%23mermaid-0 .marker%7bfill:%23333333%3bstroke:%23333333%3b%7d%23mermaid-0 .marker.cross%7bstroke:%23333333%3b%7d%23mermaid-0 svg%7bfont-family:arial%2csans-serif%3bfont-size:16px%3b%7d%23mermaid-0 p%7bmargin:0%3b%7d%23mermaid-0 .actor%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-0 text.actor%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-0 .actor-line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-0 .innerArc%7bstroke-width:1.5%3bstroke-dasharray:none%3b%7d%23mermaid-0 .messageLine0%7bstroke-width:1.5%3bstroke-dasharray:none%3bstroke:%23333%3b%7d%23mermaid-0 .messageLine1%7bstroke-width:1.5%3bstroke-dasharray:2%2c2%3bstroke:%23333%3b%7d%23mermaid-0 %23arrowhead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-0 .sequenceNumber%7bfill:white%3b%7d%23mermaid-0 %23sequencenumber%7bfill:%23333%3b%7d%23mermaid-0 %23crosshead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-0 .messageText%7bfill:%23333%3bstroke:none%3b%7d%23mermaid-0 .labelBox%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-0 .labelText%2c%23mermaid-0 .labelText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-0 .loopText%2c%23mermaid-0 .loopText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-0 .loopLine%7bstroke-width:2px%3bstroke-dasharray:2%2c2%3bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-0 .note%7bstroke:%23aaaa33%3bfill:%23fff5ad%3b%7d%23mermaid-0 .noteText%2c%23mermaid-0 .noteText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-0 .activation0%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-0 .activation1%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-0 .activation2%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-0 .actorPopupMenu%7bposition:absolute%3b%7d%23mermaid-0 .actorPopupMenuPanel%7bposition:absolute%3bfill:%23ECECFF%3bbox-shadow:0px 8px 16px 0px rgba(0%2c0%2c0%2c0.2)%3bfilter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4))%3b%7d%23mermaid-0 .actor-man line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-0 .actor-man circle%2c%23mermaid-0 line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3bstroke-width:2px%3b%7d%23mermaid-0 :root%7b--mermaid-font-family:arial%2csans-serif%3b%7d%3c/style%3e%3cg/%3e%3cdefs%3e%3csymbol id=&amp;#x27;computer&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;database&amp;#x27; fill-rule=&amp;#x27;evenodd&amp;#x27; clip-rule=&amp;#x27;evenodd&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;clock&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;arrowhead&amp;#x27; refX=&amp;#x27;7.9&amp;#x27; refY=&amp;#x27;5&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;12&amp;#x27; markerHeight=&amp;#x27;12&amp;#x27; orient=&amp;#x27;auto-start-reverse&amp;#x27;%3e%3cpath d=&amp;#x27;M -1 0 L 10 5 L 0 10 z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;crosshead&amp;#x27; markerWidth=&amp;#x27;15&amp;#x27; markerHeight=&amp;#x27;8&amp;#x27; orient=&amp;#x27;auto&amp;#x27; refX=&amp;#x27;4&amp;#x27; refY=&amp;#x27;4.5&amp;#x27;%3e%3cpath fill=&amp;#x27;none&amp;#x27; stroke=&amp;#x27;black&amp;#x27; stroke-width=&amp;#x27;1pt&amp;#x27; d=&amp;#x27;M 1%2c2 L 6%2c7 M 6%2c2 L 1%2c7&amp;#x27; style=&amp;#x27;stroke-dasharray: 0%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;filled-head&amp;#x27; refX=&amp;#x27;15.5&amp;#x27; refY=&amp;#x27;7&amp;#x27; markerWidth=&amp;#x27;20&amp;#x27; markerHeight=&amp;#x27;28&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3cpath d=&amp;#x27;M 18%2c7 L9%2c13 L14%2c7 L9%2c1 Z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;sequencenumber&amp;#x27; refX=&amp;#x27;15&amp;#x27; refY=&amp;#x27;15&amp;#x27; markerWidth=&amp;#x27;60&amp;#x27; markerHeight=&amp;#x27;40&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3ccircle cx=&amp;#x27;15&amp;#x27; cy=&amp;#x27;15&amp;#x27; r=&amp;#x27;6&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cg class=&amp;#x27;actor-man actor-top&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso0&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;25&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms0&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;33&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;33&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;60&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;45&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;60&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;10&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;67.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg class=&amp;#x27;actor-man actor-bottom&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso0&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;110&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;130&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms0&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;118&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;118&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;145&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;130&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;130&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;145&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;95&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;152.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/svg%3e&quot; width=&quot;250&quot;&gt;
&lt;p&gt;I use the &lt;code&gt;actor&lt;/code&gt; to represent users of the system. Very often, they are the people who trigger some codeflow that I am interested in.&lt;/p&gt;
&lt;p&gt;You can also generate lifelines via &lt;code&gt;participant &amp;#x3C;name&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  actor User&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  participant UI&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;img alt=&quot;&quot; height=&quot;171&quot; id=&quot;mermaid-1&quot; src=&quot;data:image/svg+xml,%3csvg id=&amp;#x27;mermaid-1&amp;#x27; width=&amp;#x27;100%25&amp;#x27; xmlns=&amp;#x27;http://www.w3.org/2000/svg&amp;#x27; xmlns:xlink=&amp;#x27;http://www.w3.org/1999/xlink&amp;#x27; style=&amp;#x27;max-width: 450px%3b&amp;#x27; viewBox=&amp;#x27;-50 -10 450 171&amp;#x27; role=&amp;#x27;graphics-document document&amp;#x27; aria-roledescription=&amp;#x27;sequence&amp;#x27;%3e%3cg%3e%3crect x=&amp;#x27;200&amp;#x27; y=&amp;#x27;85&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;UI&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;275&amp;#x27; y=&amp;#x27;117.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;275&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUI%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg/%3e%3cg%3e%3cline id=&amp;#x27;actor2&amp;#x27; x1=&amp;#x27;275&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;275&amp;#x27; y2=&amp;#x27;85&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;UI&amp;#x27;/%3e%3cg id=&amp;#x27;root-2&amp;#x27;%3e%3crect x=&amp;#x27;200&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;UI&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;275&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;275&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUI%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor1&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;80&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;85&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;User&amp;#x27;/%3e%3c/g%3e%3cstyle%3e%23mermaid-1%7bfont-family:arial%2csans-serif%3bfont-size:16px%3bfill:%23333%3b%7d%40keyframes edge-animation-frame%7bfrom%7bstroke-dashoffset:0%3b%7d%7d%40keyframes dash%7bto%7bstroke-dashoffset:0%3b%7d%7d%23mermaid-1 .edge-animation-slow%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 50s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-1 .edge-animation-fast%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 20s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-1 .error-icon%7bfill:%23552222%3b%7d%23mermaid-1 .error-text%7bfill:%23552222%3bstroke:%23552222%3b%7d%23mermaid-1 .edge-thickness-normal%7bstroke-width:1px%3b%7d%23mermaid-1 .edge-thickness-thick%7bstroke-width:3.5px%3b%7d%23mermaid-1 .edge-pattern-solid%7bstroke-dasharray:0%3b%7d%23mermaid-1 .edge-thickness-invisible%7bstroke-width:0%3bfill:none%3b%7d%23mermaid-1 .edge-pattern-dashed%7bstroke-dasharray:3%3b%7d%23mermaid-1 .edge-pattern-dotted%7bstroke-dasharray:2%3b%7d%23mermaid-1 .marker%7bfill:%23333333%3bstroke:%23333333%3b%7d%23mermaid-1 .marker.cross%7bstroke:%23333333%3b%7d%23mermaid-1 svg%7bfont-family:arial%2csans-serif%3bfont-size:16px%3b%7d%23mermaid-1 p%7bmargin:0%3b%7d%23mermaid-1 .actor%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-1 text.actor%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-1 .actor-line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-1 .innerArc%7bstroke-width:1.5%3bstroke-dasharray:none%3b%7d%23mermaid-1 .messageLine0%7bstroke-width:1.5%3bstroke-dasharray:none%3bstroke:%23333%3b%7d%23mermaid-1 .messageLine1%7bstroke-width:1.5%3bstroke-dasharray:2%2c2%3bstroke:%23333%3b%7d%23mermaid-1 %23arrowhead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-1 .sequenceNumber%7bfill:white%3b%7d%23mermaid-1 %23sequencenumber%7bfill:%23333%3b%7d%23mermaid-1 %23crosshead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-1 .messageText%7bfill:%23333%3bstroke:none%3b%7d%23mermaid-1 .labelBox%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-1 .labelText%2c%23mermaid-1 .labelText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-1 .loopText%2c%23mermaid-1 .loopText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-1 .loopLine%7bstroke-width:2px%3bstroke-dasharray:2%2c2%3bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-1 .note%7bstroke:%23aaaa33%3bfill:%23fff5ad%3b%7d%23mermaid-1 .noteText%2c%23mermaid-1 .noteText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-1 .activation0%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-1 .activation1%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-1 .activation2%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-1 .actorPopupMenu%7bposition:absolute%3b%7d%23mermaid-1 .actorPopupMenuPanel%7bposition:absolute%3bfill:%23ECECFF%3bbox-shadow:0px 8px 16px 0px rgba(0%2c0%2c0%2c0.2)%3bfilter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4))%3b%7d%23mermaid-1 .actor-man line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-1 .actor-man circle%2c%23mermaid-1 line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3bstroke-width:2px%3b%7d%23mermaid-1 :root%7b--mermaid-font-family:arial%2csans-serif%3b%7d%3c/style%3e%3cg/%3e%3cdefs%3e%3csymbol id=&amp;#x27;computer&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;database&amp;#x27; fill-rule=&amp;#x27;evenodd&amp;#x27; clip-rule=&amp;#x27;evenodd&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;clock&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;arrowhead&amp;#x27; refX=&amp;#x27;7.9&amp;#x27; refY=&amp;#x27;5&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;12&amp;#x27; markerHeight=&amp;#x27;12&amp;#x27; orient=&amp;#x27;auto-start-reverse&amp;#x27;%3e%3cpath d=&amp;#x27;M -1 0 L 10 5 L 0 10 z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;crosshead&amp;#x27; markerWidth=&amp;#x27;15&amp;#x27; markerHeight=&amp;#x27;8&amp;#x27; orient=&amp;#x27;auto&amp;#x27; refX=&amp;#x27;4&amp;#x27; refY=&amp;#x27;4.5&amp;#x27;%3e%3cpath fill=&amp;#x27;none&amp;#x27; stroke=&amp;#x27;black&amp;#x27; stroke-width=&amp;#x27;1pt&amp;#x27; d=&amp;#x27;M 1%2c2 L 6%2c7 M 6%2c2 L 1%2c7&amp;#x27; style=&amp;#x27;stroke-dasharray: 0%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;filled-head&amp;#x27; refX=&amp;#x27;15.5&amp;#x27; refY=&amp;#x27;7&amp;#x27; markerWidth=&amp;#x27;20&amp;#x27; markerHeight=&amp;#x27;28&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3cpath d=&amp;#x27;M 18%2c7 L9%2c13 L14%2c7 L9%2c1 Z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;sequencenumber&amp;#x27; refX=&amp;#x27;15&amp;#x27; refY=&amp;#x27;15&amp;#x27; markerWidth=&amp;#x27;60&amp;#x27; markerHeight=&amp;#x27;40&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3ccircle cx=&amp;#x27;15&amp;#x27; cy=&amp;#x27;15&amp;#x27; r=&amp;#x27;6&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cg class=&amp;#x27;actor-man actor-top&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso1&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;25&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms1&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;33&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;33&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;60&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;45&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;60&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;10&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;67.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg class=&amp;#x27;actor-man actor-bottom&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso2&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;110&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;130&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms2&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;118&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;118&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;145&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;130&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;130&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;145&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;95&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;152.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/svg%3e&quot; width=&quot;450&quot;&gt;
&lt;p&gt;These &lt;code&gt;participant&lt;/code&gt; objects are used to represent the various files/classes/components that the sequence diagram aims to capture.&lt;/p&gt;
&lt;p&gt;Then, to illustrate messages between entities, you can use &lt;code&gt;-&gt;&gt;&lt;/code&gt; for solid lines and &lt;code&gt;--&gt;&gt;&lt;/code&gt; for dashed lines (often associated with return values). After each line, you have to specify the message through &lt;code&gt;: &amp;#x3C;message&gt;&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  actor User&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  participant UI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  User -&gt;&gt; UI : click big red button &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  UI --&gt;&gt; User : &quot;Don&apos;t click the button!&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;img alt=&quot;&quot; height=&quot;259&quot; id=&quot;mermaid-2&quot; src=&quot;data:image/svg+xml,%3csvg id=&amp;#x27;mermaid-2&amp;#x27; width=&amp;#x27;100%25&amp;#x27; xmlns=&amp;#x27;http://www.w3.org/2000/svg&amp;#x27; xmlns:xlink=&amp;#x27;http://www.w3.org/1999/xlink&amp;#x27; style=&amp;#x27;max-width: 484px%3b&amp;#x27; viewBox=&amp;#x27;-50 -10 484 259&amp;#x27; role=&amp;#x27;graphics-document document&amp;#x27; aria-roledescription=&amp;#x27;sequence&amp;#x27;%3e%3cg%3e%3crect x=&amp;#x27;234&amp;#x27; y=&amp;#x27;173&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;UI&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;309&amp;#x27; y=&amp;#x27;205.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;309&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUI%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg/%3e%3cg%3e%3cline id=&amp;#x27;actor4&amp;#x27; x1=&amp;#x27;309&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;309&amp;#x27; y2=&amp;#x27;173&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;UI&amp;#x27;/%3e%3cg id=&amp;#x27;root-4&amp;#x27;%3e%3crect x=&amp;#x27;234&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;UI&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;309&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;309&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUI%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor3&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;80&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;173&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;User&amp;#x27;/%3e%3c/g%3e%3cstyle%3e%23mermaid-2%7bfont-family:arial%2csans-serif%3bfont-size:16px%3bfill:%23333%3b%7d%40keyframes edge-animation-frame%7bfrom%7bstroke-dashoffset:0%3b%7d%7d%40keyframes dash%7bto%7bstroke-dashoffset:0%3b%7d%7d%23mermaid-2 .edge-animation-slow%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 50s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-2 .edge-animation-fast%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 20s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-2 .error-icon%7bfill:%23552222%3b%7d%23mermaid-2 .error-text%7bfill:%23552222%3bstroke:%23552222%3b%7d%23mermaid-2 .edge-thickness-normal%7bstroke-width:1px%3b%7d%23mermaid-2 .edge-thickness-thick%7bstroke-width:3.5px%3b%7d%23mermaid-2 .edge-pattern-solid%7bstroke-dasharray:0%3b%7d%23mermaid-2 .edge-thickness-invisible%7bstroke-width:0%3bfill:none%3b%7d%23mermaid-2 .edge-pattern-dashed%7bstroke-dasharray:3%3b%7d%23mermaid-2 .edge-pattern-dotted%7bstroke-dasharray:2%3b%7d%23mermaid-2 .marker%7bfill:%23333333%3bstroke:%23333333%3b%7d%23mermaid-2 .marker.cross%7bstroke:%23333333%3b%7d%23mermaid-2 svg%7bfont-family:arial%2csans-serif%3bfont-size:16px%3b%7d%23mermaid-2 p%7bmargin:0%3b%7d%23mermaid-2 .actor%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-2 text.actor%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-2 .actor-line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-2 .innerArc%7bstroke-width:1.5%3bstroke-dasharray:none%3b%7d%23mermaid-2 .messageLine0%7bstroke-width:1.5%3bstroke-dasharray:none%3bstroke:%23333%3b%7d%23mermaid-2 .messageLine1%7bstroke-width:1.5%3bstroke-dasharray:2%2c2%3bstroke:%23333%3b%7d%23mermaid-2 %23arrowhead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-2 .sequenceNumber%7bfill:white%3b%7d%23mermaid-2 %23sequencenumber%7bfill:%23333%3b%7d%23mermaid-2 %23crosshead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-2 .messageText%7bfill:%23333%3bstroke:none%3b%7d%23mermaid-2 .labelBox%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-2 .labelText%2c%23mermaid-2 .labelText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-2 .loopText%2c%23mermaid-2 .loopText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-2 .loopLine%7bstroke-width:2px%3bstroke-dasharray:2%2c2%3bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-2 .note%7bstroke:%23aaaa33%3bfill:%23fff5ad%3b%7d%23mermaid-2 .noteText%2c%23mermaid-2 .noteText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-2 .activation0%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-2 .activation1%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-2 .activation2%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-2 .actorPopupMenu%7bposition:absolute%3b%7d%23mermaid-2 .actorPopupMenuPanel%7bposition:absolute%3bfill:%23ECECFF%3bbox-shadow:0px 8px 16px 0px rgba(0%2c0%2c0%2c0.2)%3bfilter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4))%3b%7d%23mermaid-2 .actor-man line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-2 .actor-man circle%2c%23mermaid-2 line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3bstroke-width:2px%3b%7d%23mermaid-2 :root%7b--mermaid-font-family:arial%2csans-serif%3b%7d%3c/style%3e%3cg/%3e%3cdefs%3e%3csymbol id=&amp;#x27;computer&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;database&amp;#x27; fill-rule=&amp;#x27;evenodd&amp;#x27; clip-rule=&amp;#x27;evenodd&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;clock&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;arrowhead&amp;#x27; refX=&amp;#x27;7.9&amp;#x27; refY=&amp;#x27;5&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;12&amp;#x27; markerHeight=&amp;#x27;12&amp;#x27; orient=&amp;#x27;auto-start-reverse&amp;#x27;%3e%3cpath d=&amp;#x27;M -1 0 L 10 5 L 0 10 z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;crosshead&amp;#x27; markerWidth=&amp;#x27;15&amp;#x27; markerHeight=&amp;#x27;8&amp;#x27; orient=&amp;#x27;auto&amp;#x27; refX=&amp;#x27;4&amp;#x27; refY=&amp;#x27;4.5&amp;#x27;%3e%3cpath fill=&amp;#x27;none&amp;#x27; stroke=&amp;#x27;black&amp;#x27; stroke-width=&amp;#x27;1pt&amp;#x27; d=&amp;#x27;M 1%2c2 L 6%2c7 M 6%2c2 L 1%2c7&amp;#x27; style=&amp;#x27;stroke-dasharray: 0%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;filled-head&amp;#x27; refX=&amp;#x27;15.5&amp;#x27; refY=&amp;#x27;7&amp;#x27; markerWidth=&amp;#x27;20&amp;#x27; markerHeight=&amp;#x27;28&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3cpath d=&amp;#x27;M 18%2c7 L9%2c13 L14%2c7 L9%2c1 Z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;sequencenumber&amp;#x27; refX=&amp;#x27;15&amp;#x27; refY=&amp;#x27;15&amp;#x27; markerWidth=&amp;#x27;60&amp;#x27; markerHeight=&amp;#x27;40&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3ccircle cx=&amp;#x27;15&amp;#x27; cy=&amp;#x27;15&amp;#x27; r=&amp;#x27;6&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cg class=&amp;#x27;actor-man actor-top&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso3&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;25&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms3&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;33&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;33&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;60&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;45&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;60&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;10&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;67.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3ctext x=&amp;#x27;191&amp;#x27; y=&amp;#x27;80&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eclick big red button%3c/text%3e%3cline x1=&amp;#x27;76&amp;#x27; y1=&amp;#x27;109&amp;#x27; x2=&amp;#x27;305&amp;#x27; y2=&amp;#x27;109&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;194&amp;#x27; y=&amp;#x27;124&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3e&amp;#x27;Don&amp;#x27;t click the button!&amp;#x27;%3c/text%3e%3cline x1=&amp;#x27;308&amp;#x27; y1=&amp;#x27;153&amp;#x27; x2=&amp;#x27;79&amp;#x27; y2=&amp;#x27;153&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3cg class=&amp;#x27;actor-man actor-bottom&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso4&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;198&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;218&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms4&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;206&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;206&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;233&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;218&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;218&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;233&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;183&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;240.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/svg%3e&quot; width=&quot;484&quot;&gt;
&lt;p&gt;The messages can either be function call signatures, or descriptions of the function calls and return types.&lt;/p&gt;
&lt;p&gt;Loops can be expressed using the &lt;code&gt;loop &amp;#x3C;name&gt; &amp;#x3C;condition&gt; ... end&lt;/code&gt; syntax:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  actor User&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  participant UI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  participant API&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  User -&gt;&gt; UI : subscribe to data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  loop polling&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    UI -&gt;&gt; API : fetch data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    API --&gt;&gt; UI : return data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    UI --&gt;&gt; User : display data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;img alt=&quot;&quot; height=&quot;402&quot; id=&quot;mermaid-3&quot; src=&quot;data:image/svg+xml,%3csvg id=&amp;#x27;mermaid-3&amp;#x27; width=&amp;#x27;100%25&amp;#x27; xmlns=&amp;#x27;http://www.w3.org/2000/svg&amp;#x27; xmlns:xlink=&amp;#x27;http://www.w3.org/1999/xlink&amp;#x27; style=&amp;#x27;max-width: 650px%3b&amp;#x27; viewBox=&amp;#x27;-50 -10 650 402&amp;#x27; role=&amp;#x27;graphics-document document&amp;#x27; aria-roledescription=&amp;#x27;sequence&amp;#x27;%3e%3cg%3e%3crect x=&amp;#x27;400&amp;#x27; y=&amp;#x27;316&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;API&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;475&amp;#x27; y=&amp;#x27;348.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;475&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eAPI%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg%3e%3crect x=&amp;#x27;200&amp;#x27; y=&amp;#x27;316&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;UI&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;275&amp;#x27; y=&amp;#x27;348.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;275&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUI%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg/%3e%3cg%3e%3cline id=&amp;#x27;actor7&amp;#x27; x1=&amp;#x27;475&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;475&amp;#x27; y2=&amp;#x27;316&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;API&amp;#x27;/%3e%3cg id=&amp;#x27;root-7&amp;#x27;%3e%3crect x=&amp;#x27;400&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;API&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;475&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;475&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eAPI%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor6&amp;#x27; x1=&amp;#x27;275&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;275&amp;#x27; y2=&amp;#x27;316&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;UI&amp;#x27;/%3e%3cg id=&amp;#x27;root-6&amp;#x27;%3e%3crect x=&amp;#x27;200&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;UI&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;275&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;275&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUI%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor5&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;80&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;316&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;User&amp;#x27;/%3e%3c/g%3e%3cstyle%3e%23mermaid-3%7bfont-family:arial%2csans-serif%3bfont-size:16px%3bfill:%23333%3b%7d%40keyframes edge-animation-frame%7bfrom%7bstroke-dashoffset:0%3b%7d%7d%40keyframes dash%7bto%7bstroke-dashoffset:0%3b%7d%7d%23mermaid-3 .edge-animation-slow%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 50s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-3 .edge-animation-fast%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 20s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-3 .error-icon%7bfill:%23552222%3b%7d%23mermaid-3 .error-text%7bfill:%23552222%3bstroke:%23552222%3b%7d%23mermaid-3 .edge-thickness-normal%7bstroke-width:1px%3b%7d%23mermaid-3 .edge-thickness-thick%7bstroke-width:3.5px%3b%7d%23mermaid-3 .edge-pattern-solid%7bstroke-dasharray:0%3b%7d%23mermaid-3 .edge-thickness-invisible%7bstroke-width:0%3bfill:none%3b%7d%23mermaid-3 .edge-pattern-dashed%7bstroke-dasharray:3%3b%7d%23mermaid-3 .edge-pattern-dotted%7bstroke-dasharray:2%3b%7d%23mermaid-3 .marker%7bfill:%23333333%3bstroke:%23333333%3b%7d%23mermaid-3 .marker.cross%7bstroke:%23333333%3b%7d%23mermaid-3 svg%7bfont-family:arial%2csans-serif%3bfont-size:16px%3b%7d%23mermaid-3 p%7bmargin:0%3b%7d%23mermaid-3 .actor%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-3 text.actor%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-3 .actor-line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-3 .innerArc%7bstroke-width:1.5%3bstroke-dasharray:none%3b%7d%23mermaid-3 .messageLine0%7bstroke-width:1.5%3bstroke-dasharray:none%3bstroke:%23333%3b%7d%23mermaid-3 .messageLine1%7bstroke-width:1.5%3bstroke-dasharray:2%2c2%3bstroke:%23333%3b%7d%23mermaid-3 %23arrowhead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-3 .sequenceNumber%7bfill:white%3b%7d%23mermaid-3 %23sequencenumber%7bfill:%23333%3b%7d%23mermaid-3 %23crosshead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-3 .messageText%7bfill:%23333%3bstroke:none%3b%7d%23mermaid-3 .labelBox%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-3 .labelText%2c%23mermaid-3 .labelText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-3 .loopText%2c%23mermaid-3 .loopText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-3 .loopLine%7bstroke-width:2px%3bstroke-dasharray:2%2c2%3bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-3 .note%7bstroke:%23aaaa33%3bfill:%23fff5ad%3b%7d%23mermaid-3 .noteText%2c%23mermaid-3 .noteText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-3 .activation0%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-3 .activation1%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-3 .activation2%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-3 .actorPopupMenu%7bposition:absolute%3b%7d%23mermaid-3 .actorPopupMenuPanel%7bposition:absolute%3bfill:%23ECECFF%3bbox-shadow:0px 8px 16px 0px rgba(0%2c0%2c0%2c0.2)%3bfilter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4))%3b%7d%23mermaid-3 .actor-man line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-3 .actor-man circle%2c%23mermaid-3 line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3bstroke-width:2px%3b%7d%23mermaid-3 :root%7b--mermaid-font-family:arial%2csans-serif%3b%7d%3c/style%3e%3cg/%3e%3cdefs%3e%3csymbol id=&amp;#x27;computer&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;database&amp;#x27; fill-rule=&amp;#x27;evenodd&amp;#x27; clip-rule=&amp;#x27;evenodd&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;clock&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;arrowhead&amp;#x27; refX=&amp;#x27;7.9&amp;#x27; refY=&amp;#x27;5&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;12&amp;#x27; markerHeight=&amp;#x27;12&amp;#x27; orient=&amp;#x27;auto-start-reverse&amp;#x27;%3e%3cpath d=&amp;#x27;M -1 0 L 10 5 L 0 10 z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;crosshead&amp;#x27; markerWidth=&amp;#x27;15&amp;#x27; markerHeight=&amp;#x27;8&amp;#x27; orient=&amp;#x27;auto&amp;#x27; refX=&amp;#x27;4&amp;#x27; refY=&amp;#x27;4.5&amp;#x27;%3e%3cpath fill=&amp;#x27;none&amp;#x27; stroke=&amp;#x27;black&amp;#x27; stroke-width=&amp;#x27;1pt&amp;#x27; d=&amp;#x27;M 1%2c2 L 6%2c7 M 6%2c2 L 1%2c7&amp;#x27; style=&amp;#x27;stroke-dasharray: 0%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;filled-head&amp;#x27; refX=&amp;#x27;15.5&amp;#x27; refY=&amp;#x27;7&amp;#x27; markerWidth=&amp;#x27;20&amp;#x27; markerHeight=&amp;#x27;28&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3cpath d=&amp;#x27;M 18%2c7 L9%2c13 L14%2c7 L9%2c1 Z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;sequencenumber&amp;#x27; refX=&amp;#x27;15&amp;#x27; refY=&amp;#x27;15&amp;#x27; markerWidth=&amp;#x27;60&amp;#x27; markerHeight=&amp;#x27;40&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3ccircle cx=&amp;#x27;15&amp;#x27; cy=&amp;#x27;15&amp;#x27; r=&amp;#x27;6&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cg%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;119&amp;#x27; x2=&amp;#x27;486&amp;#x27; y2=&amp;#x27;119&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;486&amp;#x27; y1=&amp;#x27;119&amp;#x27; x2=&amp;#x27;486&amp;#x27; y2=&amp;#x27;296&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;296&amp;#x27; x2=&amp;#x27;486&amp;#x27; y2=&amp;#x27;296&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;119&amp;#x27; x2=&amp;#x27;64&amp;#x27; y2=&amp;#x27;296&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cpolygon points=&amp;#x27;64%2c119 114%2c119 114%2c132 105.6%2c139 64%2c139&amp;#x27; class=&amp;#x27;labelBox&amp;#x27;/%3e%3ctext x=&amp;#x27;89&amp;#x27; y=&amp;#x27;132&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;labelText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eloop%3c/text%3e%3ctext x=&amp;#x27;300&amp;#x27; y=&amp;#x27;137&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; class=&amp;#x27;loopText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;300&amp;#x27;%3e%5bpolling%5d%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg class=&amp;#x27;actor-man actor-top&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso5&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;25&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms5&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;33&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;33&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;60&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;45&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;60&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;10&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;67.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3ctext x=&amp;#x27;174&amp;#x27; y=&amp;#x27;80&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3esubscribe to data%3c/text%3e%3cline x1=&amp;#x27;76&amp;#x27; y1=&amp;#x27;109&amp;#x27; x2=&amp;#x27;271&amp;#x27; y2=&amp;#x27;109&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;374&amp;#x27; y=&amp;#x27;169&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3efetch data%3c/text%3e%3cline x1=&amp;#x27;276&amp;#x27; y1=&amp;#x27;198&amp;#x27; x2=&amp;#x27;471&amp;#x27; y2=&amp;#x27;198&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;377&amp;#x27; y=&amp;#x27;213&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3ereturn data%3c/text%3e%3cline x1=&amp;#x27;474&amp;#x27; y1=&amp;#x27;242&amp;#x27; x2=&amp;#x27;279&amp;#x27; y2=&amp;#x27;242&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;177&amp;#x27; y=&amp;#x27;257&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3edisplay data%3c/text%3e%3cline x1=&amp;#x27;274&amp;#x27; y1=&amp;#x27;286&amp;#x27; x2=&amp;#x27;79&amp;#x27; y2=&amp;#x27;286&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3cg class=&amp;#x27;actor-man actor-bottom&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso7&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;341&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;361&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms7&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;349&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;349&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;376&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;361&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;361&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;376&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;326&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;383.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/svg%3e&quot; width=&quot;650&quot;&gt;
&lt;p&gt;You can also specify “alternative” code paths (or branches) using &lt;code&gt;alt &amp;#x3C;condition&gt; ... else &amp;#x3C;else&gt; ... end&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  actor User&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  participant UI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  participant API&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  User -&gt;&gt; UI : subscribe to data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  loop polling&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    UI -&gt;&gt; API : fetch data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    alt has data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      API --&gt;&gt; UI : return data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      UI --&gt;&gt; User : display data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    else no data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      API --&gt;&gt; UI : no data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      UI --&gt;&gt; User : &quot;no data found&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;img alt=&quot;&quot; height=&quot;590&quot; id=&quot;mermaid-4&quot; src=&quot;data:image/svg+xml,%3csvg id=&amp;#x27;mermaid-4&amp;#x27; width=&amp;#x27;100%25&amp;#x27; xmlns=&amp;#x27;http://www.w3.org/2000/svg&amp;#x27; xmlns:xlink=&amp;#x27;http://www.w3.org/1999/xlink&amp;#x27; style=&amp;#x27;max-width: 650px%3b&amp;#x27; viewBox=&amp;#x27;-50 -10 650 590&amp;#x27; role=&amp;#x27;graphics-document document&amp;#x27; aria-roledescription=&amp;#x27;sequence&amp;#x27;%3e%3cg%3e%3crect x=&amp;#x27;400&amp;#x27; y=&amp;#x27;504&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;API&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;475&amp;#x27; y=&amp;#x27;536.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;475&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eAPI%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg%3e%3crect x=&amp;#x27;200&amp;#x27; y=&amp;#x27;504&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;UI&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;275&amp;#x27; y=&amp;#x27;536.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;275&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUI%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg/%3e%3cg%3e%3cline id=&amp;#x27;actor10&amp;#x27; x1=&amp;#x27;475&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;475&amp;#x27; y2=&amp;#x27;504&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;API&amp;#x27;/%3e%3cg id=&amp;#x27;root-10&amp;#x27;%3e%3crect x=&amp;#x27;400&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;API&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;475&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;475&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eAPI%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor9&amp;#x27; x1=&amp;#x27;275&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;275&amp;#x27; y2=&amp;#x27;504&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;UI&amp;#x27;/%3e%3cg id=&amp;#x27;root-9&amp;#x27;%3e%3crect x=&amp;#x27;200&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;UI&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;275&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;275&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUI%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor8&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;80&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;504&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;User&amp;#x27;/%3e%3c/g%3e%3cstyle%3e%23mermaid-4%7bfont-family:arial%2csans-serif%3bfont-size:16px%3bfill:%23333%3b%7d%40keyframes edge-animation-frame%7bfrom%7bstroke-dashoffset:0%3b%7d%7d%40keyframes dash%7bto%7bstroke-dashoffset:0%3b%7d%7d%23mermaid-4 .edge-animation-slow%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 50s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-4 .edge-animation-fast%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 20s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-4 .error-icon%7bfill:%23552222%3b%7d%23mermaid-4 .error-text%7bfill:%23552222%3bstroke:%23552222%3b%7d%23mermaid-4 .edge-thickness-normal%7bstroke-width:1px%3b%7d%23mermaid-4 .edge-thickness-thick%7bstroke-width:3.5px%3b%7d%23mermaid-4 .edge-pattern-solid%7bstroke-dasharray:0%3b%7d%23mermaid-4 .edge-thickness-invisible%7bstroke-width:0%3bfill:none%3b%7d%23mermaid-4 .edge-pattern-dashed%7bstroke-dasharray:3%3b%7d%23mermaid-4 .edge-pattern-dotted%7bstroke-dasharray:2%3b%7d%23mermaid-4 .marker%7bfill:%23333333%3bstroke:%23333333%3b%7d%23mermaid-4 .marker.cross%7bstroke:%23333333%3b%7d%23mermaid-4 svg%7bfont-family:arial%2csans-serif%3bfont-size:16px%3b%7d%23mermaid-4 p%7bmargin:0%3b%7d%23mermaid-4 .actor%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-4 text.actor%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-4 .actor-line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-4 .innerArc%7bstroke-width:1.5%3bstroke-dasharray:none%3b%7d%23mermaid-4 .messageLine0%7bstroke-width:1.5%3bstroke-dasharray:none%3bstroke:%23333%3b%7d%23mermaid-4 .messageLine1%7bstroke-width:1.5%3bstroke-dasharray:2%2c2%3bstroke:%23333%3b%7d%23mermaid-4 %23arrowhead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-4 .sequenceNumber%7bfill:white%3b%7d%23mermaid-4 %23sequencenumber%7bfill:%23333%3b%7d%23mermaid-4 %23crosshead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-4 .messageText%7bfill:%23333%3bstroke:none%3b%7d%23mermaid-4 .labelBox%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-4 .labelText%2c%23mermaid-4 .labelText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-4 .loopText%2c%23mermaid-4 .loopText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-4 .loopLine%7bstroke-width:2px%3bstroke-dasharray:2%2c2%3bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-4 .note%7bstroke:%23aaaa33%3bfill:%23fff5ad%3b%7d%23mermaid-4 .noteText%2c%23mermaid-4 .noteText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-4 .activation0%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-4 .activation1%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-4 .activation2%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-4 .actorPopupMenu%7bposition:absolute%3b%7d%23mermaid-4 .actorPopupMenuPanel%7bposition:absolute%3bfill:%23ECECFF%3bbox-shadow:0px 8px 16px 0px rgba(0%2c0%2c0%2c0.2)%3bfilter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4))%3b%7d%23mermaid-4 .actor-man line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-4 .actor-man circle%2c%23mermaid-4 line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3bstroke-width:2px%3b%7d%23mermaid-4 :root%7b--mermaid-font-family:arial%2csans-serif%3b%7d%3c/style%3e%3cg/%3e%3cdefs%3e%3csymbol id=&amp;#x27;computer&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;database&amp;#x27; fill-rule=&amp;#x27;evenodd&amp;#x27; clip-rule=&amp;#x27;evenodd&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;clock&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;arrowhead&amp;#x27; refX=&amp;#x27;7.9&amp;#x27; refY=&amp;#x27;5&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;12&amp;#x27; markerHeight=&amp;#x27;12&amp;#x27; orient=&amp;#x27;auto-start-reverse&amp;#x27;%3e%3cpath d=&amp;#x27;M -1 0 L 10 5 L 0 10 z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;crosshead&amp;#x27; markerWidth=&amp;#x27;15&amp;#x27; markerHeight=&amp;#x27;8&amp;#x27; orient=&amp;#x27;auto&amp;#x27; refX=&amp;#x27;4&amp;#x27; refY=&amp;#x27;4.5&amp;#x27;%3e%3cpath fill=&amp;#x27;none&amp;#x27; stroke=&amp;#x27;black&amp;#x27; stroke-width=&amp;#x27;1pt&amp;#x27; d=&amp;#x27;M 1%2c2 L 6%2c7 M 6%2c2 L 1%2c7&amp;#x27; style=&amp;#x27;stroke-dasharray: 0%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;filled-head&amp;#x27; refX=&amp;#x27;15.5&amp;#x27; refY=&amp;#x27;7&amp;#x27; markerWidth=&amp;#x27;20&amp;#x27; markerHeight=&amp;#x27;28&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3cpath d=&amp;#x27;M 18%2c7 L9%2c13 L14%2c7 L9%2c1 Z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;sequencenumber&amp;#x27; refX=&amp;#x27;15&amp;#x27; refY=&amp;#x27;15&amp;#x27; markerWidth=&amp;#x27;60&amp;#x27; markerHeight=&amp;#x27;40&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3ccircle cx=&amp;#x27;15&amp;#x27; cy=&amp;#x27;15&amp;#x27; r=&amp;#x27;6&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cg%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;208&amp;#x27; x2=&amp;#x27;486&amp;#x27; y2=&amp;#x27;208&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;486&amp;#x27; y1=&amp;#x27;208&amp;#x27; x2=&amp;#x27;486&amp;#x27; y2=&amp;#x27;474&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;474&amp;#x27; x2=&amp;#x27;486&amp;#x27; y2=&amp;#x27;474&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;208&amp;#x27; x2=&amp;#x27;64&amp;#x27; y2=&amp;#x27;474&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;346&amp;#x27; x2=&amp;#x27;486&amp;#x27; y2=&amp;#x27;346&amp;#x27; class=&amp;#x27;loopLine&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b&amp;#x27;/%3e%3cpolygon points=&amp;#x27;64%2c208 114%2c208 114%2c221 105.6%2c228 64%2c228&amp;#x27; class=&amp;#x27;labelBox&amp;#x27;/%3e%3ctext x=&amp;#x27;89&amp;#x27; y=&amp;#x27;221&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;labelText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3ealt%3c/text%3e%3ctext x=&amp;#x27;300&amp;#x27; y=&amp;#x27;226&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; class=&amp;#x27;loopText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;300&amp;#x27;%3e%5bhas data%5d%3c/tspan%3e%3c/text%3e%3ctext x=&amp;#x27;275&amp;#x27; y=&amp;#x27;364&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; class=&amp;#x27;loopText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3e%5bno data%5d%3c/text%3e%3c/g%3e%3cg%3e%3cline x1=&amp;#x27;54&amp;#x27; y1=&amp;#x27;119&amp;#x27; x2=&amp;#x27;496&amp;#x27; y2=&amp;#x27;119&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;496&amp;#x27; y1=&amp;#x27;119&amp;#x27; x2=&amp;#x27;496&amp;#x27; y2=&amp;#x27;484&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;54&amp;#x27; y1=&amp;#x27;484&amp;#x27; x2=&amp;#x27;496&amp;#x27; y2=&amp;#x27;484&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;54&amp;#x27; y1=&amp;#x27;119&amp;#x27; x2=&amp;#x27;54&amp;#x27; y2=&amp;#x27;484&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cpolygon points=&amp;#x27;54%2c119 104%2c119 104%2c132 95.6%2c139 54%2c139&amp;#x27; class=&amp;#x27;labelBox&amp;#x27;/%3e%3ctext x=&amp;#x27;79&amp;#x27; y=&amp;#x27;132&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;labelText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eloop%3c/text%3e%3ctext x=&amp;#x27;300&amp;#x27; y=&amp;#x27;137&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; class=&amp;#x27;loopText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;300&amp;#x27;%3e%5bpolling%5d%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg class=&amp;#x27;actor-man actor-top&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso8&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;25&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms8&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;33&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;33&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;60&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;45&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;60&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;10&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;67.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3ctext x=&amp;#x27;174&amp;#x27; y=&amp;#x27;80&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3esubscribe to data%3c/text%3e%3cline x1=&amp;#x27;76&amp;#x27; y1=&amp;#x27;109&amp;#x27; x2=&amp;#x27;271&amp;#x27; y2=&amp;#x27;109&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;374&amp;#x27; y=&amp;#x27;169&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3efetch data%3c/text%3e%3cline x1=&amp;#x27;276&amp;#x27; y1=&amp;#x27;198&amp;#x27; x2=&amp;#x27;471&amp;#x27; y2=&amp;#x27;198&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;377&amp;#x27; y=&amp;#x27;258&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3ereturn data%3c/text%3e%3cline x1=&amp;#x27;474&amp;#x27; y1=&amp;#x27;287&amp;#x27; x2=&amp;#x27;279&amp;#x27; y2=&amp;#x27;287&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;177&amp;#x27; y=&amp;#x27;302&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3edisplay data%3c/text%3e%3cline x1=&amp;#x27;274&amp;#x27; y1=&amp;#x27;331&amp;#x27; x2=&amp;#x27;79&amp;#x27; y2=&amp;#x27;331&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;377&amp;#x27; y=&amp;#x27;391&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eno data%3c/text%3e%3cline x1=&amp;#x27;474&amp;#x27; y1=&amp;#x27;420&amp;#x27; x2=&amp;#x27;279&amp;#x27; y2=&amp;#x27;420&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;177&amp;#x27; y=&amp;#x27;435&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3e&amp;#x27;no data found&amp;#x27;%3c/text%3e%3cline x1=&amp;#x27;274&amp;#x27; y1=&amp;#x27;464&amp;#x27; x2=&amp;#x27;79&amp;#x27; y2=&amp;#x27;464&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3cg class=&amp;#x27;actor-man actor-bottom&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso10&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;529&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;549&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms10&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;537&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;537&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;564&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;549&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;549&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;564&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;514&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;571.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/svg%3e&quot; width=&quot;650&quot;&gt;
&lt;p&gt;You can also enable sequence numbers by adding &lt;code&gt;autonumber&lt;/code&gt; to the top of the diagram:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  autonumber&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  actor User&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  participant UI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  participant API&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  User -&gt;&gt; UI : subscribe to data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  loop polling&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    UI -&gt;&gt; API : fetch data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    API --&gt;&gt; UI : return data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    UI --&gt;&gt; User : display data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;img alt=&quot;&quot; height=&quot;402&quot; id=&quot;mermaid-5&quot; src=&quot;data:image/svg+xml,%3csvg id=&amp;#x27;mermaid-5&amp;#x27; width=&amp;#x27;100%25&amp;#x27; xmlns=&amp;#x27;http://www.w3.org/2000/svg&amp;#x27; xmlns:xlink=&amp;#x27;http://www.w3.org/1999/xlink&amp;#x27; style=&amp;#x27;max-width: 650px%3b&amp;#x27; viewBox=&amp;#x27;-50 -10 650 402&amp;#x27; role=&amp;#x27;graphics-document document&amp;#x27; aria-roledescription=&amp;#x27;sequence&amp;#x27;%3e%3cg%3e%3crect x=&amp;#x27;400&amp;#x27; y=&amp;#x27;316&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;API&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;475&amp;#x27; y=&amp;#x27;348.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;475&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eAPI%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg%3e%3crect x=&amp;#x27;200&amp;#x27; y=&amp;#x27;316&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;UI&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;275&amp;#x27; y=&amp;#x27;348.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;275&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUI%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg/%3e%3cg%3e%3cline id=&amp;#x27;actor13&amp;#x27; x1=&amp;#x27;475&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;475&amp;#x27; y2=&amp;#x27;316&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;API&amp;#x27;/%3e%3cg id=&amp;#x27;root-13&amp;#x27;%3e%3crect x=&amp;#x27;400&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;API&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;475&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;475&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eAPI%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor12&amp;#x27; x1=&amp;#x27;275&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;275&amp;#x27; y2=&amp;#x27;316&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;UI&amp;#x27;/%3e%3cg id=&amp;#x27;root-12&amp;#x27;%3e%3crect x=&amp;#x27;200&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;UI&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;275&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;275&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUI%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor11&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;80&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;316&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;User&amp;#x27;/%3e%3c/g%3e%3cstyle%3e%23mermaid-5%7bfont-family:arial%2csans-serif%3bfont-size:16px%3bfill:%23333%3b%7d%40keyframes edge-animation-frame%7bfrom%7bstroke-dashoffset:0%3b%7d%7d%40keyframes dash%7bto%7bstroke-dashoffset:0%3b%7d%7d%23mermaid-5 .edge-animation-slow%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 50s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-5 .edge-animation-fast%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 20s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-5 .error-icon%7bfill:%23552222%3b%7d%23mermaid-5 .error-text%7bfill:%23552222%3bstroke:%23552222%3b%7d%23mermaid-5 .edge-thickness-normal%7bstroke-width:1px%3b%7d%23mermaid-5 .edge-thickness-thick%7bstroke-width:3.5px%3b%7d%23mermaid-5 .edge-pattern-solid%7bstroke-dasharray:0%3b%7d%23mermaid-5 .edge-thickness-invisible%7bstroke-width:0%3bfill:none%3b%7d%23mermaid-5 .edge-pattern-dashed%7bstroke-dasharray:3%3b%7d%23mermaid-5 .edge-pattern-dotted%7bstroke-dasharray:2%3b%7d%23mermaid-5 .marker%7bfill:%23333333%3bstroke:%23333333%3b%7d%23mermaid-5 .marker.cross%7bstroke:%23333333%3b%7d%23mermaid-5 svg%7bfont-family:arial%2csans-serif%3bfont-size:16px%3b%7d%23mermaid-5 p%7bmargin:0%3b%7d%23mermaid-5 .actor%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-5 text.actor%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-5 .actor-line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-5 .innerArc%7bstroke-width:1.5%3bstroke-dasharray:none%3b%7d%23mermaid-5 .messageLine0%7bstroke-width:1.5%3bstroke-dasharray:none%3bstroke:%23333%3b%7d%23mermaid-5 .messageLine1%7bstroke-width:1.5%3bstroke-dasharray:2%2c2%3bstroke:%23333%3b%7d%23mermaid-5 %23arrowhead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-5 .sequenceNumber%7bfill:white%3b%7d%23mermaid-5 %23sequencenumber%7bfill:%23333%3b%7d%23mermaid-5 %23crosshead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-5 .messageText%7bfill:%23333%3bstroke:none%3b%7d%23mermaid-5 .labelBox%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-5 .labelText%2c%23mermaid-5 .labelText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-5 .loopText%2c%23mermaid-5 .loopText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-5 .loopLine%7bstroke-width:2px%3bstroke-dasharray:2%2c2%3bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-5 .note%7bstroke:%23aaaa33%3bfill:%23fff5ad%3b%7d%23mermaid-5 .noteText%2c%23mermaid-5 .noteText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-5 .activation0%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-5 .activation1%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-5 .activation2%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-5 .actorPopupMenu%7bposition:absolute%3b%7d%23mermaid-5 .actorPopupMenuPanel%7bposition:absolute%3bfill:%23ECECFF%3bbox-shadow:0px 8px 16px 0px rgba(0%2c0%2c0%2c0.2)%3bfilter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4))%3b%7d%23mermaid-5 .actor-man line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-5 .actor-man circle%2c%23mermaid-5 line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3bstroke-width:2px%3b%7d%23mermaid-5 :root%7b--mermaid-font-family:arial%2csans-serif%3b%7d%3c/style%3e%3cg/%3e%3cdefs%3e%3csymbol id=&amp;#x27;computer&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;database&amp;#x27; fill-rule=&amp;#x27;evenodd&amp;#x27; clip-rule=&amp;#x27;evenodd&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;clock&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;arrowhead&amp;#x27; refX=&amp;#x27;7.9&amp;#x27; refY=&amp;#x27;5&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;12&amp;#x27; markerHeight=&amp;#x27;12&amp;#x27; orient=&amp;#x27;auto-start-reverse&amp;#x27;%3e%3cpath d=&amp;#x27;M -1 0 L 10 5 L 0 10 z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;crosshead&amp;#x27; markerWidth=&amp;#x27;15&amp;#x27; markerHeight=&amp;#x27;8&amp;#x27; orient=&amp;#x27;auto&amp;#x27; refX=&amp;#x27;4&amp;#x27; refY=&amp;#x27;4.5&amp;#x27;%3e%3cpath fill=&amp;#x27;none&amp;#x27; stroke=&amp;#x27;black&amp;#x27; stroke-width=&amp;#x27;1pt&amp;#x27; d=&amp;#x27;M 1%2c2 L 6%2c7 M 6%2c2 L 1%2c7&amp;#x27; style=&amp;#x27;stroke-dasharray: 0%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;filled-head&amp;#x27; refX=&amp;#x27;15.5&amp;#x27; refY=&amp;#x27;7&amp;#x27; markerWidth=&amp;#x27;20&amp;#x27; markerHeight=&amp;#x27;28&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3cpath d=&amp;#x27;M 18%2c7 L9%2c13 L14%2c7 L9%2c1 Z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;sequencenumber&amp;#x27; refX=&amp;#x27;15&amp;#x27; refY=&amp;#x27;15&amp;#x27; markerWidth=&amp;#x27;60&amp;#x27; markerHeight=&amp;#x27;40&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3ccircle cx=&amp;#x27;15&amp;#x27; cy=&amp;#x27;15&amp;#x27; r=&amp;#x27;6&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cg%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;119&amp;#x27; x2=&amp;#x27;486&amp;#x27; y2=&amp;#x27;119&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;486&amp;#x27; y1=&amp;#x27;119&amp;#x27; x2=&amp;#x27;486&amp;#x27; y2=&amp;#x27;296&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;296&amp;#x27; x2=&amp;#x27;486&amp;#x27; y2=&amp;#x27;296&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;119&amp;#x27; x2=&amp;#x27;64&amp;#x27; y2=&amp;#x27;296&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cpolygon points=&amp;#x27;64%2c119 114%2c119 114%2c132 105.6%2c139 64%2c139&amp;#x27; class=&amp;#x27;labelBox&amp;#x27;/%3e%3ctext x=&amp;#x27;89&amp;#x27; y=&amp;#x27;132&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;labelText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eloop%3c/text%3e%3ctext x=&amp;#x27;300&amp;#x27; y=&amp;#x27;137&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; class=&amp;#x27;loopText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;300&amp;#x27;%3e%5bpolling%5d%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg class=&amp;#x27;actor-man actor-top&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso11&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;25&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms11&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;33&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;33&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;60&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;45&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;60&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;10&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;67.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3ctext x=&amp;#x27;174&amp;#x27; y=&amp;#x27;80&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3esubscribe to data%3c/text%3e%3cline x1=&amp;#x27;76&amp;#x27; y1=&amp;#x27;109&amp;#x27; x2=&amp;#x27;271&amp;#x27; y2=&amp;#x27;109&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3cline x1=&amp;#x27;76&amp;#x27; y1=&amp;#x27;109&amp;#x27; x2=&amp;#x27;76&amp;#x27; y2=&amp;#x27;109&amp;#x27; stroke-width=&amp;#x27;0&amp;#x27; marker-start=&amp;#x27;url(%23sequencenumber)&amp;#x27;/%3e%3ctext x=&amp;#x27;76&amp;#x27; y=&amp;#x27;113&amp;#x27; font-family=&amp;#x27;sans-serif&amp;#x27; font-size=&amp;#x27;12px&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; class=&amp;#x27;sequenceNumber&amp;#x27;%3e1%3c/text%3e%3ctext x=&amp;#x27;374&amp;#x27; y=&amp;#x27;169&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3efetch data%3c/text%3e%3cline x1=&amp;#x27;276&amp;#x27; y1=&amp;#x27;198&amp;#x27; x2=&amp;#x27;471&amp;#x27; y2=&amp;#x27;198&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3cline x1=&amp;#x27;276&amp;#x27; y1=&amp;#x27;198&amp;#x27; x2=&amp;#x27;276&amp;#x27; y2=&amp;#x27;198&amp;#x27; stroke-width=&amp;#x27;0&amp;#x27; marker-start=&amp;#x27;url(%23sequencenumber)&amp;#x27;/%3e%3ctext x=&amp;#x27;276&amp;#x27; y=&amp;#x27;202&amp;#x27; font-family=&amp;#x27;sans-serif&amp;#x27; font-size=&amp;#x27;12px&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; class=&amp;#x27;sequenceNumber&amp;#x27;%3e2%3c/text%3e%3ctext x=&amp;#x27;377&amp;#x27; y=&amp;#x27;213&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3ereturn data%3c/text%3e%3cline x1=&amp;#x27;474&amp;#x27; y1=&amp;#x27;242&amp;#x27; x2=&amp;#x27;279&amp;#x27; y2=&amp;#x27;242&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3cline x1=&amp;#x27;474&amp;#x27; y1=&amp;#x27;242&amp;#x27; x2=&amp;#x27;474&amp;#x27; y2=&amp;#x27;242&amp;#x27; stroke-width=&amp;#x27;0&amp;#x27; marker-start=&amp;#x27;url(%23sequencenumber)&amp;#x27;/%3e%3ctext x=&amp;#x27;474&amp;#x27; y=&amp;#x27;246&amp;#x27; font-family=&amp;#x27;sans-serif&amp;#x27; font-size=&amp;#x27;12px&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; class=&amp;#x27;sequenceNumber&amp;#x27;%3e3%3c/text%3e%3ctext x=&amp;#x27;177&amp;#x27; y=&amp;#x27;257&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3edisplay data%3c/text%3e%3cline x1=&amp;#x27;274&amp;#x27; y1=&amp;#x27;286&amp;#x27; x2=&amp;#x27;79&amp;#x27; y2=&amp;#x27;286&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3cline x1=&amp;#x27;274&amp;#x27; y1=&amp;#x27;286&amp;#x27; x2=&amp;#x27;274&amp;#x27; y2=&amp;#x27;286&amp;#x27; stroke-width=&amp;#x27;0&amp;#x27; marker-start=&amp;#x27;url(%23sequencenumber)&amp;#x27;/%3e%3ctext x=&amp;#x27;274&amp;#x27; y=&amp;#x27;290&amp;#x27; font-family=&amp;#x27;sans-serif&amp;#x27; font-size=&amp;#x27;12px&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; class=&amp;#x27;sequenceNumber&amp;#x27;%3e4%3c/text%3e%3cg class=&amp;#x27;actor-man actor-bottom&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso13&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;341&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;361&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms13&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;349&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;349&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;376&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;361&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;361&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;376&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;326&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;383.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/svg%3e&quot; width=&quot;650&quot;&gt;
&lt;p&gt;That’s all you really need to know. There are plenty of other notations like &lt;code&gt;par&lt;/code&gt; and &lt;code&gt;note&lt;/code&gt;, but I generally do not use them.&lt;/p&gt;
&lt;p&gt;Now that you have a general understanding of Mermaid, I can now introduce how I approach using sequence diagrams through the concept of “fidelity”.&lt;/p&gt;
&lt;h2 id=&quot;sequence-diagram-fidelities&quot;&gt;Sequence diagram fidelities&lt;/h2&gt;
&lt;p&gt;I borrow the term “fidelity” from prototyping, which refers to the level of detail, accuracy, and realism of a prototype compared to the final product. [2]&lt;/p&gt;
&lt;p&gt;Similar to prototyping, there are the three levels of fidelity I work with:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Low-fidelity&lt;/li&gt;
&lt;li&gt;Medium-fidelity&lt;/li&gt;
&lt;li&gt;High-fidelity&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The choice of fidelity is clear when you ask the question, “How much details do I need to capture in the diagram?”&lt;/p&gt;
&lt;h3 id=&quot;low-fidelity&quot;&gt;Low-fidelity&lt;/h3&gt;
&lt;p&gt;Low-fidelity sequence diagrams focus on component-component or user-component interactions. A lot of low-level details are omitted, such as individual function calls.&lt;/p&gt;
&lt;p&gt;Often, I use these as a starting point to understand the “big picture” of a system.&lt;/p&gt;
&lt;p&gt;For instance, this was a low-fidelity sequence diagram I created to understand how Supabase authentication works.&lt;/p&gt;
&lt;img alt=&quot;&quot; height=&quot;523&quot; id=&quot;mermaid-6&quot; src=&quot;data:image/svg+xml,%3csvg id=&amp;#x27;mermaid-6&amp;#x27; width=&amp;#x27;100%25&amp;#x27; xmlns=&amp;#x27;http://www.w3.org/2000/svg&amp;#x27; xmlns:xlink=&amp;#x27;http://www.w3.org/1999/xlink&amp;#x27; style=&amp;#x27;max-width: 1194px%3b&amp;#x27; viewBox=&amp;#x27;-50 -10 1194 523&amp;#x27; role=&amp;#x27;graphics-document document&amp;#x27; aria-roledescription=&amp;#x27;sequence&amp;#x27;%3e%3cg%3e%3crect x=&amp;#x27;944&amp;#x27; y=&amp;#x27;437&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;api&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;1019&amp;#x27; y=&amp;#x27;469.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;1019&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eAPI%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg%3e%3crect x=&amp;#x27;744&amp;#x27; y=&amp;#x27;437&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;sb&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;819&amp;#x27; y=&amp;#x27;469.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;819&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eSupabase%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg%3e%3crect x=&amp;#x27;292&amp;#x27; y=&amp;#x27;437&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;d&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;367&amp;#x27; y=&amp;#x27;469.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;367&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eDashboard%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg/%3e%3cg%3e%3cline id=&amp;#x27;actor17&amp;#x27; x1=&amp;#x27;1019&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;1019&amp;#x27; y2=&amp;#x27;437&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;api&amp;#x27;/%3e%3cg id=&amp;#x27;root-17&amp;#x27;%3e%3crect x=&amp;#x27;944&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;api&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;1019&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;1019&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eAPI%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor16&amp;#x27; x1=&amp;#x27;819&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;819&amp;#x27; y2=&amp;#x27;437&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;sb&amp;#x27;/%3e%3cg id=&amp;#x27;root-16&amp;#x27;%3e%3crect x=&amp;#x27;744&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;sb&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;819&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;819&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eSupabase%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor15&amp;#x27; x1=&amp;#x27;367&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;367&amp;#x27; y2=&amp;#x27;437&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;d&amp;#x27;/%3e%3cg id=&amp;#x27;root-15&amp;#x27;%3e%3crect x=&amp;#x27;292&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;d&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;367&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;367&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eDashboard%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor14&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;80&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;437&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;u&amp;#x27;/%3e%3c/g%3e%3cstyle%3e%23mermaid-6%7bfont-family:arial%2csans-serif%3bfont-size:16px%3bfill:%23333%3b%7d%40keyframes edge-animation-frame%7bfrom%7bstroke-dashoffset:0%3b%7d%7d%40keyframes dash%7bto%7bstroke-dashoffset:0%3b%7d%7d%23mermaid-6 .edge-animation-slow%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 50s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-6 .edge-animation-fast%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 20s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-6 .error-icon%7bfill:%23552222%3b%7d%23mermaid-6 .error-text%7bfill:%23552222%3bstroke:%23552222%3b%7d%23mermaid-6 .edge-thickness-normal%7bstroke-width:1px%3b%7d%23mermaid-6 .edge-thickness-thick%7bstroke-width:3.5px%3b%7d%23mermaid-6 .edge-pattern-solid%7bstroke-dasharray:0%3b%7d%23mermaid-6 .edge-thickness-invisible%7bstroke-width:0%3bfill:none%3b%7d%23mermaid-6 .edge-pattern-dashed%7bstroke-dasharray:3%3b%7d%23mermaid-6 .edge-pattern-dotted%7bstroke-dasharray:2%3b%7d%23mermaid-6 .marker%7bfill:%23333333%3bstroke:%23333333%3b%7d%23mermaid-6 .marker.cross%7bstroke:%23333333%3b%7d%23mermaid-6 svg%7bfont-family:arial%2csans-serif%3bfont-size:16px%3b%7d%23mermaid-6 p%7bmargin:0%3b%7d%23mermaid-6 .actor%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-6 text.actor%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-6 .actor-line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-6 .innerArc%7bstroke-width:1.5%3bstroke-dasharray:none%3b%7d%23mermaid-6 .messageLine0%7bstroke-width:1.5%3bstroke-dasharray:none%3bstroke:%23333%3b%7d%23mermaid-6 .messageLine1%7bstroke-width:1.5%3bstroke-dasharray:2%2c2%3bstroke:%23333%3b%7d%23mermaid-6 %23arrowhead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-6 .sequenceNumber%7bfill:white%3b%7d%23mermaid-6 %23sequencenumber%7bfill:%23333%3b%7d%23mermaid-6 %23crosshead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-6 .messageText%7bfill:%23333%3bstroke:none%3b%7d%23mermaid-6 .labelBox%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-6 .labelText%2c%23mermaid-6 .labelText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-6 .loopText%2c%23mermaid-6 .loopText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-6 .loopLine%7bstroke-width:2px%3bstroke-dasharray:2%2c2%3bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-6 .note%7bstroke:%23aaaa33%3bfill:%23fff5ad%3b%7d%23mermaid-6 .noteText%2c%23mermaid-6 .noteText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-6 .activation0%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-6 .activation1%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-6 .activation2%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-6 .actorPopupMenu%7bposition:absolute%3b%7d%23mermaid-6 .actorPopupMenuPanel%7bposition:absolute%3bfill:%23ECECFF%3bbox-shadow:0px 8px 16px 0px rgba(0%2c0%2c0%2c0.2)%3bfilter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4))%3b%7d%23mermaid-6 .actor-man line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-6 .actor-man circle%2c%23mermaid-6 line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3bstroke-width:2px%3b%7d%23mermaid-6 :root%7b--mermaid-font-family:arial%2csans-serif%3b%7d%3c/style%3e%3cg/%3e%3cdefs%3e%3csymbol id=&amp;#x27;computer&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;database&amp;#x27; fill-rule=&amp;#x27;evenodd&amp;#x27; clip-rule=&amp;#x27;evenodd&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;clock&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;arrowhead&amp;#x27; refX=&amp;#x27;7.9&amp;#x27; refY=&amp;#x27;5&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;12&amp;#x27; markerHeight=&amp;#x27;12&amp;#x27; orient=&amp;#x27;auto-start-reverse&amp;#x27;%3e%3cpath d=&amp;#x27;M -1 0 L 10 5 L 0 10 z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;crosshead&amp;#x27; markerWidth=&amp;#x27;15&amp;#x27; markerHeight=&amp;#x27;8&amp;#x27; orient=&amp;#x27;auto&amp;#x27; refX=&amp;#x27;4&amp;#x27; refY=&amp;#x27;4.5&amp;#x27;%3e%3cpath fill=&amp;#x27;none&amp;#x27; stroke=&amp;#x27;black&amp;#x27; stroke-width=&amp;#x27;1pt&amp;#x27; d=&amp;#x27;M 1%2c2 L 6%2c7 M 6%2c2 L 1%2c7&amp;#x27; style=&amp;#x27;stroke-dasharray: 0%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;filled-head&amp;#x27; refX=&amp;#x27;15.5&amp;#x27; refY=&amp;#x27;7&amp;#x27; markerWidth=&amp;#x27;20&amp;#x27; markerHeight=&amp;#x27;28&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3cpath d=&amp;#x27;M 18%2c7 L9%2c13 L14%2c7 L9%2c1 Z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;sequencenumber&amp;#x27; refX=&amp;#x27;15&amp;#x27; refY=&amp;#x27;15&amp;#x27; markerWidth=&amp;#x27;60&amp;#x27; markerHeight=&amp;#x27;40&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3ccircle cx=&amp;#x27;15&amp;#x27; cy=&amp;#x27;15&amp;#x27; r=&amp;#x27;6&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cg class=&amp;#x27;actor-man actor-top&amp;#x27; name=&amp;#x27;u&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso14&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;25&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms14&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;33&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;33&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;60&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;45&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;60&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;10&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;67.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3ctext x=&amp;#x27;220&amp;#x27; y=&amp;#x27;80&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eLogin with email/Google/Github%3c/text%3e%3cline x1=&amp;#x27;76&amp;#x27; y1=&amp;#x27;109&amp;#x27; x2=&amp;#x27;363&amp;#x27; y2=&amp;#x27;109&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;592&amp;#x27; y=&amp;#x27;124&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eLogin with provider%3c/text%3e%3cline x1=&amp;#x27;368&amp;#x27; y1=&amp;#x27;153&amp;#x27; x2=&amp;#x27;815&amp;#x27; y2=&amp;#x27;153&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;595&amp;#x27; y=&amp;#x27;168&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eRedirect on successful authentication to /auth/... route%3c/text%3e%3cline x1=&amp;#x27;818&amp;#x27; y1=&amp;#x27;197&amp;#x27; x2=&amp;#x27;371&amp;#x27; y2=&amp;#x27;197&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;692&amp;#x27; y=&amp;#x27;212&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eSubmit user signup if necessary%3c/text%3e%3cline x1=&amp;#x27;368&amp;#x27; y1=&amp;#x27;241&amp;#x27; x2=&amp;#x27;1015&amp;#x27; y2=&amp;#x27;241&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;592&amp;#x27; y=&amp;#x27;256&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eSet logged in user (Supabase handles JWT)%3c/text%3e%3cline x1=&amp;#x27;368&amp;#x27; y1=&amp;#x27;285&amp;#x27; x2=&amp;#x27;815&amp;#x27; y2=&amp;#x27;285&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;220&amp;#x27; y=&amp;#x27;300&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eUser action%3c/text%3e%3cline x1=&amp;#x27;76&amp;#x27; y1=&amp;#x27;329&amp;#x27; x2=&amp;#x27;363&amp;#x27; y2=&amp;#x27;329&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;592&amp;#x27; y=&amp;#x27;344&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eFetch JWT of current user%3c/text%3e%3cline x1=&amp;#x27;368&amp;#x27; y1=&amp;#x27;373&amp;#x27; x2=&amp;#x27;815&amp;#x27; y2=&amp;#x27;373&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;692&amp;#x27; y=&amp;#x27;388&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3ePerform API%3c/text%3e%3cline x1=&amp;#x27;368&amp;#x27; y1=&amp;#x27;417&amp;#x27; x2=&amp;#x27;1015&amp;#x27; y2=&amp;#x27;417&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3cg class=&amp;#x27;actor-man actor-bottom&amp;#x27; name=&amp;#x27;u&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso17&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;462&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;482&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms17&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;470&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;470&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;497&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;482&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;482&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;497&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;447&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;504.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/svg%3e&quot; width=&quot;1194&quot;&gt;
&lt;p&gt;Rather than spending time trying to map out the individual underlying function calls, such as how user signup submission is handled, I focus on representing the system through the actor &lt;code&gt;User&lt;/code&gt; and participants &lt;code&gt;Dashboard&lt;/code&gt;, &lt;code&gt;Supabase&lt;/code&gt;, and &lt;code&gt;API&lt;/code&gt; (representing the high-level components of the system). Every message describes the high-level interactions between actors and participants.&lt;/p&gt;
&lt;p&gt;Low-fidelity sequence diagrams are very useful to give you a bird’s eye view of how a system works, and how user interactions look like. However, you may be interested in understanding how certain components work while maintaining a bird’s eye view of the entire system. This is where medium-fidelity sequence diagrams come in.&lt;/p&gt;
&lt;h3 id=&quot;medium-fidelity&quot;&gt;Medium-fidelity&lt;/h3&gt;
&lt;p&gt;Medium-fidelity sequence diagrams often involve both high-level component-component or user-component interaction, and some low-level details within these interactions.&lt;/p&gt;
&lt;p&gt;For instance, this was a medium-fidelity sequence diagram I used to understand how the Google OAuth2.0 authorization flow works (which might not be 100% accurate).&lt;/p&gt;
&lt;img alt=&quot;&quot; height=&quot;1229&quot; id=&quot;mermaid-7&quot; src=&quot;data:image/svg+xml,%3csvg id=&amp;#x27;mermaid-7&amp;#x27; width=&amp;#x27;100%25&amp;#x27; xmlns=&amp;#x27;http://www.w3.org/2000/svg&amp;#x27; xmlns:xlink=&amp;#x27;http://www.w3.org/1999/xlink&amp;#x27; style=&amp;#x27;max-width: 1245px%3b&amp;#x27; viewBox=&amp;#x27;-50 -10 1245 1229&amp;#x27; role=&amp;#x27;graphics-document document&amp;#x27; aria-roledescription=&amp;#x27;sequence&amp;#x27;%3e%3cg%3e%3crect x=&amp;#x27;995&amp;#x27; y=&amp;#x27;1143&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;Database&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;1070&amp;#x27; y=&amp;#x27;1175.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;1070&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eDatabase%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg%3e%3crect x=&amp;#x27;790&amp;#x27; y=&amp;#x27;1143&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;Server&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;865&amp;#x27; y=&amp;#x27;1175.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;865&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eServer%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg%3e%3crect x=&amp;#x27;584&amp;#x27; y=&amp;#x27;1143&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;Google&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;659&amp;#x27; y=&amp;#x27;1175.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;659&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eGoogle%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg%3e%3crect x=&amp;#x27;227&amp;#x27; y=&amp;#x27;1143&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;Client&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;302&amp;#x27; y=&amp;#x27;1175.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;302&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eClient%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg/%3e%3cg%3e%3cline id=&amp;#x27;actor22&amp;#x27; x1=&amp;#x27;1070&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;1070&amp;#x27; y2=&amp;#x27;1143&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;Database&amp;#x27;/%3e%3cg id=&amp;#x27;root-22&amp;#x27;%3e%3crect x=&amp;#x27;995&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;Database&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;1070&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;1070&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eDatabase%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor21&amp;#x27; x1=&amp;#x27;865&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;865&amp;#x27; y2=&amp;#x27;1143&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;Server&amp;#x27;/%3e%3cg id=&amp;#x27;root-21&amp;#x27;%3e%3crect x=&amp;#x27;790&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;Server&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;865&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;865&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eServer%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor20&amp;#x27; x1=&amp;#x27;659&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;659&amp;#x27; y2=&amp;#x27;1143&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;Google&amp;#x27;/%3e%3cg id=&amp;#x27;root-20&amp;#x27;%3e%3crect x=&amp;#x27;584&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;Google&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;659&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;659&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eGoogle%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor19&amp;#x27; x1=&amp;#x27;302&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;302&amp;#x27; y2=&amp;#x27;1143&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;Client&amp;#x27;/%3e%3cg id=&amp;#x27;root-19&amp;#x27;%3e%3crect x=&amp;#x27;227&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;Client&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;302&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;302&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eClient%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor18&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;80&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;1143&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;User&amp;#x27;/%3e%3c/g%3e%3cstyle%3e%23mermaid-7%7bfont-family:arial%2csans-serif%3bfont-size:16px%3bfill:%23333%3b%7d%40keyframes edge-animation-frame%7bfrom%7bstroke-dashoffset:0%3b%7d%7d%40keyframes dash%7bto%7bstroke-dashoffset:0%3b%7d%7d%23mermaid-7 .edge-animation-slow%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 50s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-7 .edge-animation-fast%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 20s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-7 .error-icon%7bfill:%23552222%3b%7d%23mermaid-7 .error-text%7bfill:%23552222%3bstroke:%23552222%3b%7d%23mermaid-7 .edge-thickness-normal%7bstroke-width:1px%3b%7d%23mermaid-7 .edge-thickness-thick%7bstroke-width:3.5px%3b%7d%23mermaid-7 .edge-pattern-solid%7bstroke-dasharray:0%3b%7d%23mermaid-7 .edge-thickness-invisible%7bstroke-width:0%3bfill:none%3b%7d%23mermaid-7 .edge-pattern-dashed%7bstroke-dasharray:3%3b%7d%23mermaid-7 .edge-pattern-dotted%7bstroke-dasharray:2%3b%7d%23mermaid-7 .marker%7bfill:%23333333%3bstroke:%23333333%3b%7d%23mermaid-7 .marker.cross%7bstroke:%23333333%3b%7d%23mermaid-7 svg%7bfont-family:arial%2csans-serif%3bfont-size:16px%3b%7d%23mermaid-7 p%7bmargin:0%3b%7d%23mermaid-7 .actor%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-7 text.actor%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-7 .actor-line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-7 .innerArc%7bstroke-width:1.5%3bstroke-dasharray:none%3b%7d%23mermaid-7 .messageLine0%7bstroke-width:1.5%3bstroke-dasharray:none%3bstroke:%23333%3b%7d%23mermaid-7 .messageLine1%7bstroke-width:1.5%3bstroke-dasharray:2%2c2%3bstroke:%23333%3b%7d%23mermaid-7 %23arrowhead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-7 .sequenceNumber%7bfill:white%3b%7d%23mermaid-7 %23sequencenumber%7bfill:%23333%3b%7d%23mermaid-7 %23crosshead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-7 .messageText%7bfill:%23333%3bstroke:none%3b%7d%23mermaid-7 .labelBox%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-7 .labelText%2c%23mermaid-7 .labelText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-7 .loopText%2c%23mermaid-7 .loopText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-7 .loopLine%7bstroke-width:2px%3bstroke-dasharray:2%2c2%3bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-7 .note%7bstroke:%23aaaa33%3bfill:%23fff5ad%3b%7d%23mermaid-7 .noteText%2c%23mermaid-7 .noteText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-7 .activation0%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-7 .activation1%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-7 .activation2%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-7 .actorPopupMenu%7bposition:absolute%3b%7d%23mermaid-7 .actorPopupMenuPanel%7bposition:absolute%3bfill:%23ECECFF%3bbox-shadow:0px 8px 16px 0px rgba(0%2c0%2c0%2c0.2)%3bfilter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4))%3b%7d%23mermaid-7 .actor-man line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-7 .actor-man circle%2c%23mermaid-7 line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3bstroke-width:2px%3b%7d%23mermaid-7 :root%7b--mermaid-font-family:arial%2csans-serif%3b%7d%3c/style%3e%3cg/%3e%3cdefs%3e%3csymbol id=&amp;#x27;computer&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;database&amp;#x27; fill-rule=&amp;#x27;evenodd&amp;#x27; clip-rule=&amp;#x27;evenodd&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;clock&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;arrowhead&amp;#x27; refX=&amp;#x27;7.9&amp;#x27; refY=&amp;#x27;5&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;12&amp;#x27; markerHeight=&amp;#x27;12&amp;#x27; orient=&amp;#x27;auto-start-reverse&amp;#x27;%3e%3cpath d=&amp;#x27;M -1 0 L 10 5 L 0 10 z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;crosshead&amp;#x27; markerWidth=&amp;#x27;15&amp;#x27; markerHeight=&amp;#x27;8&amp;#x27; orient=&amp;#x27;auto&amp;#x27; refX=&amp;#x27;4&amp;#x27; refY=&amp;#x27;4.5&amp;#x27;%3e%3cpath fill=&amp;#x27;none&amp;#x27; stroke=&amp;#x27;black&amp;#x27; stroke-width=&amp;#x27;1pt&amp;#x27; d=&amp;#x27;M 1%2c2 L 6%2c7 M 6%2c2 L 1%2c7&amp;#x27; style=&amp;#x27;stroke-dasharray: 0%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;filled-head&amp;#x27; refX=&amp;#x27;15.5&amp;#x27; refY=&amp;#x27;7&amp;#x27; markerWidth=&amp;#x27;20&amp;#x27; markerHeight=&amp;#x27;28&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3cpath d=&amp;#x27;M 18%2c7 L9%2c13 L14%2c7 L9%2c1 Z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;sequencenumber&amp;#x27; refX=&amp;#x27;15&amp;#x27; refY=&amp;#x27;15&amp;#x27; markerWidth=&amp;#x27;60&amp;#x27; markerHeight=&amp;#x27;40&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3ccircle cx=&amp;#x27;15&amp;#x27; cy=&amp;#x27;15&amp;#x27; r=&amp;#x27;6&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cg%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;547&amp;#x27; x2=&amp;#x27;1081&amp;#x27; y2=&amp;#x27;547&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;1081&amp;#x27; y1=&amp;#x27;547&amp;#x27; x2=&amp;#x27;1081&amp;#x27; y2=&amp;#x27;1123&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;1123&amp;#x27; x2=&amp;#x27;1081&amp;#x27; y2=&amp;#x27;1123&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;547&amp;#x27; x2=&amp;#x27;64&amp;#x27; y2=&amp;#x27;1123&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;685&amp;#x27; x2=&amp;#x27;1081&amp;#x27; y2=&amp;#x27;685&amp;#x27; class=&amp;#x27;loopLine&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b&amp;#x27;/%3e%3cpolygon points=&amp;#x27;64%2c547 114%2c547 114%2c560 105.6%2c567 64%2c567&amp;#x27; class=&amp;#x27;labelBox&amp;#x27;/%3e%3ctext x=&amp;#x27;89&amp;#x27; y=&amp;#x27;560&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;labelText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3ealt%3c/text%3e%3ctext x=&amp;#x27;597.5&amp;#x27; y=&amp;#x27;565&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; class=&amp;#x27;loopText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;597.5&amp;#x27;%3e%5b!is_valid%5d%3c/tspan%3e%3c/text%3e%3ctext x=&amp;#x27;572.5&amp;#x27; y=&amp;#x27;703&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; class=&amp;#x27;loopText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3e%5belse%5d%3c/text%3e%3c/g%3e%3cg class=&amp;#x27;actor-man actor-top&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso18&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;25&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms18&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;33&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;33&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;60&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;45&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;45&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;60&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;10&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;67.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3ctext x=&amp;#x27;479&amp;#x27; y=&amp;#x27;80&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eRequest token%3c/text%3e%3cline x1=&amp;#x27;303&amp;#x27; y1=&amp;#x27;109&amp;#x27; x2=&amp;#x27;655&amp;#x27; y2=&amp;#x27;109&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;187&amp;#x27; y=&amp;#x27;124&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eLogin with Google%3c/text%3e%3cline x1=&amp;#x27;76&amp;#x27; y1=&amp;#x27;153&amp;#x27; x2=&amp;#x27;298&amp;#x27; y2=&amp;#x27;153&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;479&amp;#x27; y=&amp;#x27;168&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eRedirect to Google login %26amp%3b consent page%3c/text%3e%3cline x1=&amp;#x27;303&amp;#x27; y1=&amp;#x27;197&amp;#x27; x2=&amp;#x27;655&amp;#x27; y2=&amp;#x27;197&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;482&amp;#x27; y=&amp;#x27;212&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eAuthorization code%3c/text%3e%3cline x1=&amp;#x27;658&amp;#x27; y1=&amp;#x27;241&amp;#x27; x2=&amp;#x27;306&amp;#x27; y2=&amp;#x27;241&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;479&amp;#x27; y=&amp;#x27;256&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eExchange auth code for token%3c/text%3e%3cline x1=&amp;#x27;303&amp;#x27; y1=&amp;#x27;285&amp;#x27; x2=&amp;#x27;655&amp;#x27; y2=&amp;#x27;285&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;482&amp;#x27; y=&amp;#x27;300&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eToken%3c/text%3e%3cline x1=&amp;#x27;658&amp;#x27; y1=&amp;#x27;329&amp;#x27; x2=&amp;#x27;306&amp;#x27; y2=&amp;#x27;329&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;582&amp;#x27; y=&amp;#x27;344&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3e/login%3c/text%3e%3cline x1=&amp;#x27;303&amp;#x27; y1=&amp;#x27;373&amp;#x27; x2=&amp;#x27;861&amp;#x27; y2=&amp;#x27;373&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;866&amp;#x27; y=&amp;#x27;388&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eValidate token%3c/text%3e%3cpath d=&amp;#x27;M 866%2c417 C 926%2c407 926%2c447 866%2c437&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;764&amp;#x27; y=&amp;#x27;462&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3e/tokeninfo endpoint%3c/text%3e%3cline x1=&amp;#x27;864&amp;#x27; y1=&amp;#x27;491&amp;#x27; x2=&amp;#x27;663&amp;#x27; y2=&amp;#x27;491&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;761&amp;#x27; y=&amp;#x27;506&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eis_valid%3c/text%3e%3cline x1=&amp;#x27;660&amp;#x27; y1=&amp;#x27;537&amp;#x27; x2=&amp;#x27;861&amp;#x27; y2=&amp;#x27;537&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;585&amp;#x27; y=&amp;#x27;597&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eHTTP 401 (Unauthorized)%3c/text%3e%3cline x1=&amp;#x27;864&amp;#x27; y1=&amp;#x27;626&amp;#x27; x2=&amp;#x27;306&amp;#x27; y2=&amp;#x27;626&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;190&amp;#x27; y=&amp;#x27;641&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eCannot login%3c/text%3e%3cline x1=&amp;#x27;301&amp;#x27; y1=&amp;#x27;670&amp;#x27; x2=&amp;#x27;79&amp;#x27; y2=&amp;#x27;670&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;866&amp;#x27; y=&amp;#x27;730&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eHas user%3f%3c/text%3e%3cpath d=&amp;#x27;M 866%2c759 C 926%2c749 926%2c789 866%2c779&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;966&amp;#x27; y=&amp;#x27;804&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eRetrieve user entry%3c/text%3e%3cline x1=&amp;#x27;866&amp;#x27; y1=&amp;#x27;833&amp;#x27; x2=&amp;#x27;1066&amp;#x27; y2=&amp;#x27;833&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;969&amp;#x27; y=&amp;#x27;848&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eUser%3c/text%3e%3cline x1=&amp;#x27;1069&amp;#x27; y1=&amp;#x27;877&amp;#x27; x2=&amp;#x27;869&amp;#x27; y2=&amp;#x27;877&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;866&amp;#x27; y=&amp;#x27;892&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eCreate JWT%3c/text%3e%3cpath d=&amp;#x27;M 866%2c921 C 926%2c911 926%2c951 866%2c941&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;585&amp;#x27; y=&amp;#x27;966&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eJWT%3c/text%3e%3cline x1=&amp;#x27;864&amp;#x27; y1=&amp;#x27;995&amp;#x27; x2=&amp;#x27;306&amp;#x27; y2=&amp;#x27;995&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;303&amp;#x27; y=&amp;#x27;1010&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eStore JWT%3c/text%3e%3cpath d=&amp;#x27;M 303%2c1039 C 363%2c1029 363%2c1069 303%2c1059&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;190&amp;#x27; y=&amp;#x27;1084&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eRedirect to dashboard%3c/text%3e%3cline x1=&amp;#x27;301&amp;#x27; y1=&amp;#x27;1113&amp;#x27; x2=&amp;#x27;79&amp;#x27; y2=&amp;#x27;1113&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3cg class=&amp;#x27;actor-man actor-bottom&amp;#x27; name=&amp;#x27;User&amp;#x27;%3e%3cline id=&amp;#x27;actor-man-torso22&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;1168&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;1188&amp;#x27;/%3e%3cline id=&amp;#x27;actor-man-arms22&amp;#x27; x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;1176&amp;#x27; x2=&amp;#x27;93&amp;#x27; y2=&amp;#x27;1176&amp;#x27;/%3e%3cline x1=&amp;#x27;57&amp;#x27; y1=&amp;#x27;1203&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;1188&amp;#x27;/%3e%3cline x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;1188&amp;#x27; x2=&amp;#x27;91&amp;#x27; y2=&amp;#x27;1203&amp;#x27;/%3e%3ccircle cx=&amp;#x27;75&amp;#x27; cy=&amp;#x27;1153&amp;#x27; r=&amp;#x27;15&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;1210.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-man&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eUser%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/svg%3e&quot; width=&quot;1245&quot;&gt;
&lt;p&gt;This diagram contains both high-level component-component and user-component interactions (e.g. between &lt;code&gt;Client&lt;/code&gt; and &lt;code&gt;Google&lt;/code&gt;) and some lower-level information (e.g. between &lt;code&gt;Server&lt;/code&gt; and &lt;code&gt;Database&lt;/code&gt;) where details like how the information is retrieved and what is returned is captured as individual messages.&lt;/p&gt;
&lt;p&gt;However, I prefer to avoid using medium-fidelity diagrams. As you can see, these diagrams can grow unwieldy very quickly as more high-level components are introduced, which becomes hard to understand and maintain.&lt;/p&gt;
&lt;p&gt;Instead, what I often do is create a low-fidelity sequence diagram with message numbers (using &lt;code&gt;autonumber&lt;/code&gt;), and attach additional notes (through text or as high-fidelity sequence diagrams) to each of the relevant message numbers.&lt;/p&gt;
&lt;p&gt;But for cases where the number of components are still reasonable, medium-fidelity diagrams are still a good middle ground to provide a bird’s eye view of the system while having some details fleshed out.&lt;/p&gt;
&lt;h3 id=&quot;high-fidelity&quot;&gt;High-fidelity&lt;/h3&gt;
&lt;p&gt;Rather than focusing on the “big picture” like low-fidelity or medium-fidelity sequence diagrams, high-fidelity sequence diagrams are designed to drill deep into the interaction between a very small subset of components.&lt;/p&gt;
&lt;p&gt;For instance, this was a high-fidelity sequence diagram I created to explain a change I was proposing for a &lt;a href=&quot;https://github.com/CATcher-org/CATcher/pull/1264&quot;&gt;pull request&lt;/a&gt;:&lt;/p&gt;
&lt;img alt=&quot;&quot; height=&quot;919&quot; id=&quot;mermaid-8&quot; src=&quot;data:image/svg+xml,%3csvg id=&amp;#x27;mermaid-8&amp;#x27; width=&amp;#x27;100%25&amp;#x27; xmlns=&amp;#x27;http://www.w3.org/2000/svg&amp;#x27; xmlns:xlink=&amp;#x27;http://www.w3.org/1999/xlink&amp;#x27; style=&amp;#x27;max-width: 788.5px%3b&amp;#x27; viewBox=&amp;#x27;-50 -10 788.5 919&amp;#x27; role=&amp;#x27;graphics-document document&amp;#x27; aria-roledescription=&amp;#x27;sequence&amp;#x27;%3e%3cg%3e%3crect x=&amp;#x27;538.5&amp;#x27; y=&amp;#x27;833&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;g&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;613.5&amp;#x27; y=&amp;#x27;865.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;613.5&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eGitHubService%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg%3e%3crect x=&amp;#x27;275&amp;#x27; y=&amp;#x27;833&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;i&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;350&amp;#x27; y=&amp;#x27;865.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;350&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eIssueService%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg%3e%3crect x=&amp;#x27;0&amp;#x27; y=&amp;#x27;833&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;Caller&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-bottom&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;865.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eCaller%3c/tspan%3e%3c/text%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor25&amp;#x27; x1=&amp;#x27;613.5&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;613.5&amp;#x27; y2=&amp;#x27;833&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;g&amp;#x27;/%3e%3cg id=&amp;#x27;root-25&amp;#x27;%3e%3crect x=&amp;#x27;538.5&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;g&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;613.5&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;613.5&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eGitHubService%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor24&amp;#x27; x1=&amp;#x27;350&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;350&amp;#x27; y2=&amp;#x27;833&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;i&amp;#x27;/%3e%3cg id=&amp;#x27;root-24&amp;#x27;%3e%3crect x=&amp;#x27;275&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;i&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;350&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;350&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eIssueService%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cg%3e%3cline id=&amp;#x27;actor23&amp;#x27; x1=&amp;#x27;75&amp;#x27; y1=&amp;#x27;65&amp;#x27; x2=&amp;#x27;75&amp;#x27; y2=&amp;#x27;833&amp;#x27; class=&amp;#x27;actor-line 200&amp;#x27; stroke-width=&amp;#x27;0.5px&amp;#x27; stroke=&amp;#x27;%23999&amp;#x27; name=&amp;#x27;Caller&amp;#x27;/%3e%3cg id=&amp;#x27;root-23&amp;#x27;%3e%3crect x=&amp;#x27;0&amp;#x27; y=&amp;#x27;0&amp;#x27; fill=&amp;#x27;%23eaeaea&amp;#x27; stroke=&amp;#x27;%23666&amp;#x27; width=&amp;#x27;150&amp;#x27; height=&amp;#x27;65&amp;#x27; name=&amp;#x27;Caller&amp;#x27; rx=&amp;#x27;3&amp;#x27; ry=&amp;#x27;3&amp;#x27; class=&amp;#x27;actor actor-top&amp;#x27;/%3e%3ctext x=&amp;#x27;75&amp;#x27; y=&amp;#x27;32.5&amp;#x27; dominant-baseline=&amp;#x27;central&amp;#x27; alignment-baseline=&amp;#x27;central&amp;#x27; class=&amp;#x27;actor actor-box&amp;#x27; style=&amp;#x27;text-anchor: middle%3b font-size: 16px%3b font-weight: 400%3b font-family: arial%2c sans-serif%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;75&amp;#x27; dy=&amp;#x27;0&amp;#x27;%3eCaller%3c/tspan%3e%3c/text%3e%3c/g%3e%3c/g%3e%3cstyle%3e%23mermaid-8%7bfont-family:arial%2csans-serif%3bfont-size:16px%3bfill:%23333%3b%7d%40keyframes edge-animation-frame%7bfrom%7bstroke-dashoffset:0%3b%7d%7d%40keyframes dash%7bto%7bstroke-dashoffset:0%3b%7d%7d%23mermaid-8 .edge-animation-slow%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 50s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-8 .edge-animation-fast%7bstroke-dasharray:9%2c5!important%3bstroke-dashoffset:900%3banimation:dash 20s linear infinite%3bstroke-linecap:round%3b%7d%23mermaid-8 .error-icon%7bfill:%23552222%3b%7d%23mermaid-8 .error-text%7bfill:%23552222%3bstroke:%23552222%3b%7d%23mermaid-8 .edge-thickness-normal%7bstroke-width:1px%3b%7d%23mermaid-8 .edge-thickness-thick%7bstroke-width:3.5px%3b%7d%23mermaid-8 .edge-pattern-solid%7bstroke-dasharray:0%3b%7d%23mermaid-8 .edge-thickness-invisible%7bstroke-width:0%3bfill:none%3b%7d%23mermaid-8 .edge-pattern-dashed%7bstroke-dasharray:3%3b%7d%23mermaid-8 .edge-pattern-dotted%7bstroke-dasharray:2%3b%7d%23mermaid-8 .marker%7bfill:%23333333%3bstroke:%23333333%3b%7d%23mermaid-8 .marker.cross%7bstroke:%23333333%3b%7d%23mermaid-8 svg%7bfont-family:arial%2csans-serif%3bfont-size:16px%3b%7d%23mermaid-8 p%7bmargin:0%3b%7d%23mermaid-8 .actor%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-8 text.actor%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-8 .actor-line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-8 .innerArc%7bstroke-width:1.5%3bstroke-dasharray:none%3b%7d%23mermaid-8 .messageLine0%7bstroke-width:1.5%3bstroke-dasharray:none%3bstroke:%23333%3b%7d%23mermaid-8 .messageLine1%7bstroke-width:1.5%3bstroke-dasharray:2%2c2%3bstroke:%23333%3b%7d%23mermaid-8 %23arrowhead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-8 .sequenceNumber%7bfill:white%3b%7d%23mermaid-8 %23sequencenumber%7bfill:%23333%3b%7d%23mermaid-8 %23crosshead path%7bfill:%23333%3bstroke:%23333%3b%7d%23mermaid-8 .messageText%7bfill:%23333%3bstroke:none%3b%7d%23mermaid-8 .labelBox%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-8 .labelText%2c%23mermaid-8 .labelText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-8 .loopText%2c%23mermaid-8 .loopText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-8 .loopLine%7bstroke-width:2px%3bstroke-dasharray:2%2c2%3bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3b%7d%23mermaid-8 .note%7bstroke:%23aaaa33%3bfill:%23fff5ad%3b%7d%23mermaid-8 .noteText%2c%23mermaid-8 .noteText%26gt%3btspan%7bfill:black%3bstroke:none%3b%7d%23mermaid-8 .activation0%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-8 .activation1%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-8 .activation2%7bfill:%23f4f4f4%3bstroke:%23666%3b%7d%23mermaid-8 .actorPopupMenu%7bposition:absolute%3b%7d%23mermaid-8 .actorPopupMenuPanel%7bposition:absolute%3bfill:%23ECECFF%3bbox-shadow:0px 8px 16px 0px rgba(0%2c0%2c0%2c0.2)%3bfilter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4))%3b%7d%23mermaid-8 .actor-man line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3b%7d%23mermaid-8 .actor-man circle%2c%23mermaid-8 line%7bstroke:hsl(259.6261682243%2c 59.7765363128%25%2c 87.9019607843%25)%3bfill:%23ECECFF%3bstroke-width:2px%3b%7d%23mermaid-8 :root%7b--mermaid-font-family:arial%2csans-serif%3b%7d%3c/style%3e%3cg/%3e%3cdefs%3e%3csymbol id=&amp;#x27;computer&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;database&amp;#x27; fill-rule=&amp;#x27;evenodd&amp;#x27; clip-rule=&amp;#x27;evenodd&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3csymbol id=&amp;#x27;clock&amp;#x27; width=&amp;#x27;24&amp;#x27; height=&amp;#x27;24&amp;#x27;%3e%3cpath transform=&amp;#x27;scale(.5)&amp;#x27; d=&amp;#x27;M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z&amp;#x27;/%3e%3c/symbol%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;arrowhead&amp;#x27; refX=&amp;#x27;7.9&amp;#x27; refY=&amp;#x27;5&amp;#x27; markerUnits=&amp;#x27;userSpaceOnUse&amp;#x27; markerWidth=&amp;#x27;12&amp;#x27; markerHeight=&amp;#x27;12&amp;#x27; orient=&amp;#x27;auto-start-reverse&amp;#x27;%3e%3cpath d=&amp;#x27;M -1 0 L 10 5 L 0 10 z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;crosshead&amp;#x27; markerWidth=&amp;#x27;15&amp;#x27; markerHeight=&amp;#x27;8&amp;#x27; orient=&amp;#x27;auto&amp;#x27; refX=&amp;#x27;4&amp;#x27; refY=&amp;#x27;4.5&amp;#x27;%3e%3cpath fill=&amp;#x27;none&amp;#x27; stroke=&amp;#x27;black&amp;#x27; stroke-width=&amp;#x27;1pt&amp;#x27; d=&amp;#x27;M 1%2c2 L 6%2c7 M 6%2c2 L 1%2c7&amp;#x27; style=&amp;#x27;stroke-dasharray: 0%2c 0%3b&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;filled-head&amp;#x27; refX=&amp;#x27;15.5&amp;#x27; refY=&amp;#x27;7&amp;#x27; markerWidth=&amp;#x27;20&amp;#x27; markerHeight=&amp;#x27;28&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3cpath d=&amp;#x27;M 18%2c7 L9%2c13 L14%2c7 L9%2c1 Z&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cdefs%3e%3cmarker id=&amp;#x27;sequencenumber&amp;#x27; refX=&amp;#x27;15&amp;#x27; refY=&amp;#x27;15&amp;#x27; markerWidth=&amp;#x27;60&amp;#x27; markerHeight=&amp;#x27;40&amp;#x27; orient=&amp;#x27;auto&amp;#x27;%3e%3ccircle cx=&amp;#x27;15&amp;#x27; cy=&amp;#x27;15&amp;#x27; r=&amp;#x27;6&amp;#x27;/%3e%3c/marker%3e%3c/defs%3e%3cg%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;237&amp;#x27; x2=&amp;#x27;624.5&amp;#x27; y2=&amp;#x27;237&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;624.5&amp;#x27; y1=&amp;#x27;237&amp;#x27; x2=&amp;#x27;624.5&amp;#x27; y2=&amp;#x27;813&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;813&amp;#x27; x2=&amp;#x27;624.5&amp;#x27; y2=&amp;#x27;813&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;237&amp;#x27; x2=&amp;#x27;64&amp;#x27; y2=&amp;#x27;813&amp;#x27; class=&amp;#x27;loopLine&amp;#x27;/%3e%3cline x1=&amp;#x27;64&amp;#x27; y1=&amp;#x27;611&amp;#x27; x2=&amp;#x27;624.5&amp;#x27; y2=&amp;#x27;611&amp;#x27; class=&amp;#x27;loopLine&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b&amp;#x27;/%3e%3cpolygon points=&amp;#x27;64%2c237 114%2c237 114%2c250 105.6%2c257 64%2c257&amp;#x27; class=&amp;#x27;labelBox&amp;#x27;/%3e%3ctext x=&amp;#x27;89&amp;#x27; y=&amp;#x27;250&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;labelText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3ealt%3c/text%3e%3ctext x=&amp;#x27;369.25&amp;#x27; y=&amp;#x27;255&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; class=&amp;#x27;loopText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3e%3ctspan x=&amp;#x27;369.25&amp;#x27;%3e%5bvalid fields%5d%3c/tspan%3e%3c/text%3e%3ctext x=&amp;#x27;344.25&amp;#x27; y=&amp;#x27;629&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; class=&amp;#x27;loopText&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3e%5belse%5d%3c/text%3e%3c/g%3e%3ctext x=&amp;#x27;211&amp;#x27; y=&amp;#x27;80&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3ecreateTeamResponse(Issue)%3c/text%3e%3cline x1=&amp;#x27;76&amp;#x27; y1=&amp;#x27;109&amp;#x27; x2=&amp;#x27;346&amp;#x27; y2=&amp;#x27;109&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;351&amp;#x27; y=&amp;#x27;124&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eupdateIssuePure%3c/text%3e%3cpath d=&amp;#x27;M 351%2c153 C 411%2c143 411%2c183 351%2c173&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;480&amp;#x27; y=&amp;#x27;198&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eupdateIssue%3c/text%3e%3cline x1=&amp;#x27;351&amp;#x27; y1=&amp;#x27;227&amp;#x27; x2=&amp;#x27;609.5&amp;#x27; y2=&amp;#x27;227&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;483&amp;#x27; y=&amp;#x27;287&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eGitHubIssue%3c/text%3e%3cline x1=&amp;#x27;612.5&amp;#x27; y1=&amp;#x27;316&amp;#x27; x2=&amp;#x27;354&amp;#x27; y2=&amp;#x27;316&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;480&amp;#x27; y=&amp;#x27;331&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3ecreateIssueComment%3c/text%3e%3cline x1=&amp;#x27;351&amp;#x27; y1=&amp;#x27;360&amp;#x27; x2=&amp;#x27;609.5&amp;#x27; y2=&amp;#x27;360&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;483&amp;#x27; y=&amp;#x27;375&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eGitHubComment%3c/text%3e%3cline x1=&amp;#x27;612.5&amp;#x27; y1=&amp;#x27;404&amp;#x27; x2=&amp;#x27;354&amp;#x27; y2=&amp;#x27;404&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;351&amp;#x27; y=&amp;#x27;419&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eUpdate Issue githubComments field with latest comments%3c/text%3e%3cpath d=&amp;#x27;M 351%2c448 C 411%2c438 411%2c478 351%2c468&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;351&amp;#x27; y=&amp;#x27;493&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3ecreateIssueModel(GitHubIssue)%3c/text%3e%3cpath d=&amp;#x27;M 351%2c522 C 411%2c512 411%2c552 351%2c542&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;214&amp;#x27; y=&amp;#x27;567&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eComplete%3c/text%3e%3cline x1=&amp;#x27;349&amp;#x27; y1=&amp;#x27;596&amp;#x27; x2=&amp;#x27;79&amp;#x27; y2=&amp;#x27;596&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;483&amp;#x27; y=&amp;#x27;656&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eError%3c/text%3e%3cline x1=&amp;#x27;612.5&amp;#x27; y1=&amp;#x27;685&amp;#x27; x2=&amp;#x27;354&amp;#x27; y2=&amp;#x27;685&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;351&amp;#x27; y=&amp;#x27;700&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eParse error%3c/text%3e%3cpath d=&amp;#x27;M 351%2c729 C 411%2c719 411%2c759 351%2c749&amp;#x27; class=&amp;#x27;messageLine0&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;fill: none%3b&amp;#x27;/%3e%3ctext x=&amp;#x27;214&amp;#x27; y=&amp;#x27;774&amp;#x27; text-anchor=&amp;#x27;middle&amp;#x27; dominant-baseline=&amp;#x27;middle&amp;#x27; alignment-baseline=&amp;#x27;middle&amp;#x27; class=&amp;#x27;messageText&amp;#x27; dy=&amp;#x27;1em&amp;#x27; style=&amp;#x27;font-family: arial%2c sans-serif%3b font-size: 16px%3b font-weight: 400%3b&amp;#x27;%3eTerminate operation%3c/text%3e%3cline x1=&amp;#x27;349&amp;#x27; y1=&amp;#x27;803&amp;#x27; x2=&amp;#x27;79&amp;#x27; y2=&amp;#x27;803&amp;#x27; class=&amp;#x27;messageLine1&amp;#x27; stroke-width=&amp;#x27;2&amp;#x27; stroke=&amp;#x27;none&amp;#x27; marker-end=&amp;#x27;url(%23arrowhead)&amp;#x27; style=&amp;#x27;stroke-dasharray: 3%2c 3%3b fill: none%3b&amp;#x27;/%3e%3c/svg%3e&quot; width=&quot;788.5&quot;&gt;
&lt;p&gt;Here, I focus solely on the interactions between the &lt;code&gt;IssueService&lt;/code&gt; and &lt;code&gt;GitHubService&lt;/code&gt;, with &lt;code&gt;Caller&lt;/code&gt; acting as an “anchor” for what initiates this interaction. In high-fidelity sequence diagrams, focus on mapping out the individual function calls like &lt;code&gt;createTeamReponse(Issue)&lt;/code&gt; or providing high-level descriptions of each step, explaining the “how” behind the interaction.&lt;/p&gt;
&lt;p&gt;Some functions may include many individual function calls that are not relevant to understanding the current interaction. For these cases, I typically summarize them as a high-level message. High-fidelity diagrams try to capture the relevant low-level details of the interaction, so any irrelevant details can be omitted or summarized.&lt;/p&gt;
&lt;h2 id=&quot;general-guidelines&quot;&gt;General guidelines&lt;/h2&gt;
&lt;p&gt;Now that I have established my system of creating sequence diagrams, these are some general guidelines I try to follow to keep myself sane:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Keep it to under 50 messages&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you realize that the diagram is growing extremely large, then it is probably time to break it out into separate diagrams.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Avoid adding notes within the diagram itself&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Instead, add message numbers using &lt;code&gt;autonumber&lt;/code&gt; and add notes outside of the diagram to reduce clutter.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Don’t get sucked into representing every little interaction&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Depending on your goal, you should try to aim for clarity over comprehensiveness in your messages. Save the little interactions for other sequence diagrams or notes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Treat sequence diagrams as living documentation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Upload these diagrams to your repository, revisit them, and update them as changes are made. Do what you can to keep these diagrams and notes up-to-date as it benefits both you and future maintainers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Keep asking questions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As you comb through the codebase and add the interactions to your sequence diagrams, leave questions (or &lt;code&gt;TODO&lt;/code&gt; comments) about components that you find interesting or are unsure about. If these impede your understanding of the codebase, you have found a blocker, else, these act as good things to return to down the road.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;closing&quot;&gt;Closing&lt;/h2&gt;
&lt;p&gt;That’s it! It’s a relatively simple system that I started using a few years ago and found it to be quite effective in both personal projects or during my internships, allowing me to create pull requests within hours of being introduced to a codebase.&lt;/p&gt;
&lt;p&gt;“Oh, but this feels like a lot of extra effort…” you might lament.&lt;/p&gt;
&lt;p&gt;And to that, I answer, “You are absolutely right!”&lt;/p&gt;
&lt;p&gt;This is a system that takes a bit of time to get used to, and it does add a layer of overhead to your approach to codebases. However, I think that benefit of having a living learning document/page/repository is crucial in becoming more productive as a developer, understanding systems, and realizing where your contributions fit into the “bigger picture”.&lt;/p&gt;
&lt;p&gt;I also find that the act of creating documentation and writing about the systems I interact with has made me a better communicator of my ideas and understanding. These diagrams have also helped my teammates understand the system and some have even become staples within the team’s repositories!&lt;/p&gt;
&lt;p&gt;So, give this system a go and let me know what you think! Enjoy!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;[1] &lt;a href=&quot;https://developer.ibm.com/articles/the-sequence-diagram/&quot;&gt;IBM’s introduction to sequence diagrams&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[2] &lt;a href=&quot;https://www.protopie.io/blog/low-fidelity-vs-high-fidelity-prototyping&quot;&gt;Low-Fidelity vs. High-Fidelity Prototyping: Key Differences Explained&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 25 Apr 2025 00:00:00 GMT</pubDate></item><item><title>Evolution of Resumes</title><link>https://blog.woojiahao.com/post/evolution-of-resumes</link><guid isPermaLink="true">https://blog.woojiahao.com/post/evolution-of-resumes</guid><description>&lt;p&gt;I was reading &lt;a href=&quot;https://luyangkenneth.github.io/evolution-of-resumes/&quot;&gt;Kenneth Lu’s page on his evolution of resumes&lt;/a&gt; and felt it would be interesting to look back at my past resumes and reflect on the lessons learnt at each junction, and explain my thoughts on crafting a good resume and building a strong portfolio. [1]&lt;/p&gt;
&lt;div class=&quot;callout warning&quot;&gt;&lt;p&gt;Before starting, I would like to make a disclaimer that this is by no means a definitive guide to creating a good resume, nor is it your golden ticket to landing internships. I believe a lot of my success in finding internships thus far has been a mixture of incredulous luck and technical interview preparation. Having a good resume is just one step in the process, so you should be focusing on improving all facets of the technical interview preparation process, not just your resume. [2]&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;By focusing on both resume building and developing a portfolio over the years (and with quite a bit of luck), I was able to &lt;strong&gt;secure internship offers from companies like Citadel, Palantir, Google, Paypal, and Stripe.&lt;/strong&gt; I hope that you find my experiences useful and insightful in your own journey.&lt;/p&gt;
&lt;h2 id=&quot;general-advice&quot;&gt;General advice&lt;/h2&gt;
&lt;p&gt;Your resume should follow these general principles:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Keep it to one page&lt;/li&gt;
&lt;li&gt;Highlight your most relevant experiences first&lt;/li&gt;
&lt;li&gt;Use action words (verbs) for each bullet point&lt;/li&gt;
&lt;li&gt;Use a legible font like Arial&lt;/li&gt;
&lt;li&gt;Avoid cramming content, whitespace is good&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can find more on the &lt;a href=&quot;https://www.reddit.com/r/EngineeringResumes/wiki/index/&quot;&gt;r/EngineeringResumes wiki&lt;/a&gt;, so I will not go into repeating everything.&lt;/p&gt;
&lt;h2 id=&quot;polytechnic-year-3&quot;&gt;Polytechnic year 3&lt;/h2&gt;
&lt;p&gt;I went to &lt;strong&gt;DBS Bank&lt;/strong&gt; during my polytechnic internship placement.&lt;/p&gt;
&lt;p&gt;I will admit that I was pretty “privileged” that I did not start out from absolute zero. During my first two years in polytechnic, I was building various side projects such as &lt;a href=&quot;https://github.com/woojiahao/Taiga&quot;&gt;Taiga&lt;/a&gt; and working on several school projects like &lt;a href=&quot;https://github.com/woojiahao/BookIt&quot;&gt;BookIt!&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These led me to land a short-term unofficial stint as an Android developer for MightyAim, a startup that I was introduced to by a friend, &lt;a href=&quot;https://www.linkedin.com/in/li-haoquan/&quot;&gt;Li Haoquan&lt;/a&gt;, where I was able to build &lt;em&gt;some&lt;/em&gt; experience in working on real-world engineering problems.&lt;/p&gt;
&lt;p&gt;These experiences opened the door for me to give a workshop, teaching students the fundamentals of Android development using Kotlin, a language I was obsessed with back then.&lt;/p&gt;
&lt;p&gt;So, going into my internship job hunt in my final year of polytechnic, I had the following going for me already:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A good GPA that would stand out amongst other candidates&lt;/li&gt;
&lt;li&gt;Some relevant work experience through my time with MightyAim&lt;/li&gt;
&lt;li&gt;Substantial projects with technical depth that I could talk about&lt;/li&gt;
&lt;li&gt;An interesting extracurricular activity that was relevant to tech&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;“These are great Jiahao, but what can I do if I do not have such a starting position?” you might ask.&lt;/p&gt;
&lt;p&gt;It is definitely not a lost cause, I would focus on the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Include any projects you might have worked on previously. Something is better than nothing, even if it is a school project that other students may have attempted as well.&lt;/li&gt;
&lt;li&gt;If your GPA is good, include it, it is something to be proud of.&lt;/li&gt;
&lt;li&gt;Include all past work experiences, even if it is not immediately relevant. A data entry job may not be software engineering related, but it can demonstrate that you possess some of the skills that employers might care about.&lt;/li&gt;
&lt;li&gt;Think about what employers want to see and frame your experiences and projects that way. This might differ based on the role.&lt;/li&gt;
&lt;li&gt;Pursue your interests and develop your portfolio that way, focusing on going deep rather than trying everything at a beginner level.&lt;/li&gt;
&lt;li&gt;Meet new people and network to unlock more opportunities. I am admittedly not the best at this still, but it is always worth attending events and talking to people.&lt;/li&gt;
&lt;li&gt;Make your relevant skills and experiences clear and apparent with dedicated sections and emphasis.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/evolution-of-resumes/pre-dbs.jpg&quot; alt=&quot;Polytechnic year 3&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;post-polytechnic&quot;&gt;Post polytechnic&lt;/h2&gt;
&lt;p&gt;After graduating from polytechnic, and while awaiting for my enlistment into the Singapore Armed Forces, I decided to pursue an internship in research, a field I was unfamiliar with. This led me to do an internship as a Natural Language Processing (NLP) research intern at &lt;strong&gt;DSO National Laboratories&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I kept using the same LaTeX template, but this time, I had included my experience from DBS Bank, along with a different set of projects, all self-initiated. I also started including my academic achievements, like graduating with a Diploma with Merit and receiving the IMDA Gold Medal. I also moved my skills down to the end, highlighting my work experience first.&lt;/p&gt;
&lt;p&gt;These are some comments on this resume:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Focus on including the impact of your work on your resume using concrete numbers. I don’t think I was the best at representing it then, but looking back, this was something I would have done differently.&lt;/li&gt;
&lt;li&gt;Prefer side projects over school projects. Once you have established some set of personal projects, they are often more impressive than mandatory school projects.&lt;/li&gt;
&lt;li&gt;Bubble all your experiences to the top, prioritizing experiences and projects that demonstrate your skills over simple lists of technologies you know.&lt;/li&gt;
&lt;li&gt;Use &lt;a href=&quot;https://www.colorado.edu/career/job-searching/resumes-and-cover-letters/resumes/action-verbs-use-your-resume&quot;&gt;action words (verbs)&lt;/a&gt; for each bullet point. One thing I don’t like about this resume is the fact that I placed my “role” at the start, but the bullet points should allow readers to infer the role.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/evolution-of-resumes/pre-dso.png&quot; alt=&quot;Post polytechnic&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;university-year-1&quot;&gt;University year 1&lt;/h2&gt;
&lt;p&gt;I have shared about my &lt;a href=&quot;/post/technical-interview-systems#first-failures&quot;&gt;struggles in finding an internship in the first year of university&lt;/a&gt;. Despite having relevant experiences, I did not have the right technical interview skills to overcome the interviews. [2] However, I was very fortunate to have still received three offers: one from the &lt;a href=&quot;https://www.comp.nus.edu.sg/~vwo/&quot;&gt;Computing for Voluntary Welfare Organisations (CVWO)&lt;/a&gt;, an internship that NUS students have access to, another from &lt;a href=&quot;https://nodeflair.com/&quot;&gt;Nodeflair&lt;/a&gt;, a tech career platform, and the final one from Betafi, a startup building a unified user research platform. I eventually took up the internship at &lt;strong&gt;Betafi&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I did not receive these offers because I was a good technical interviewee. Instead, I was able to leverage my experience from building past projects and technical writing.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The CVWO application process involved building a project over the winter break, and I had spent an obscene amount of time on it, refining the product. [3] The online interview was a discussion on my engineering decisions. The process was not simple, but having used the technologies in other projects reduced the barrier to entry.&lt;/li&gt;
&lt;li&gt;The Nodeflair interview process was the most similar to the traditional technical interview process. However, the questions revolved around the application of programming to solve common software engineering problems (like reversing words in a string). This process allowed me to tap into my general problem solving skills that I have developed, as opposed to knowing specific data structures and algorithms.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sherbondy&quot;&gt;Ethan Sherbondy&lt;/a&gt;, the CTO of Betafi, reached out to me via Linkedin about interning at Betafi. However, this was not because I was a “stacked” engineer, but rather because I was very deeply involved in writing about &lt;a href=&quot;https://elixir-lang.org/&quot;&gt;Elixir&lt;/a&gt;, and I had written several articles on my personal blog (here!) and for a company called AppSignal. He noticed my portfolio and reached out because Betafi was building their platform in Elixir.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key points I would hope you take away from this is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Play to your strengths. Apply to companies that have processes that best align with your strengths and interest. This may not always be possible, but there are some that are like that.&lt;/li&gt;
&lt;li&gt;Building your portfolio and doing things you are interested in matters. I do not think I would have been able to secure as many opportunities if I had not spent my time working on projects or writing technical articles about things I enjoyed.&lt;/li&gt;
&lt;li&gt;Highlight the things that make you stand out. For me, it was my teaching and writing experience, so I included those as a dedicated section.&lt;/li&gt;
&lt;li&gt;Pursue all possible opportunities. Rather than optimizing for glamorous internships, try applying for all opportunities, you never know what could happen.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/evolution-of-resumes/pre-betafi.png&quot; alt=&quot;University year 1&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;university-year-2&quot;&gt;University year 2&lt;/h2&gt;
&lt;p&gt;Learning from my struggles from the previous summer, I started preparing for technical interviews religiously [2] and eventually was very fortunate to receive offers from Citadel, Palantir (in London), Google, and Paypal. I eventually accepted the offers from &lt;strong&gt;Citadel for the summer, and Palantir for the fall&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I also added some tweaks to my resume:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Moving to Google Docs. [4]&lt;/li&gt;
&lt;li&gt;Squeezing as much content by shrinking the margins. While this felt like a good idea then, looking back, I think it would have been good if I kept some whitespace to allow readers to breathe when reading my resume.&lt;/li&gt;
&lt;li&gt;De-prioritizing old experiences. Rather than trying to fit every experience I’ve had, I decided to trim my experiences to only include my most recent three internships.&lt;/li&gt;
&lt;li&gt;Removing my polytechnic education. In Singapore, polytechnic is similar to high school, so there was no reason to include it now that I have been in university for two years.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/evolution-of-resumes/pre-citadel.png&quot; alt=&quot;University year 2&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;university-year-3&quot;&gt;University year 3&lt;/h2&gt;
&lt;p&gt;I did not apply to as many companies as I did the year before because I had other commitments and was too busy having fun in London. Naturally, I received fewer Online Assessments (OAs) and interviews, but I still managed to get interviews with companies like Hudson River Trading (HRT), Jane Street, and Stripe. I was fortunate to have friends who provided referrals to both HRT and Jane Street. Ultimately, I received an offer from Stripe.&lt;/p&gt;
&lt;p&gt;Regardless, I would still like to point out the following changes to my resume:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Moving to Typst. [5] I wanted to consistently generate sections without tweaking Google Docs.&lt;/li&gt;
&lt;li&gt;Highlighting my work authorization. I was also applying to firms in the US and UK, so having my work authorization at the very top helped to cut through the uncertainty these firms might have about my ability to work abroad. As a Singapore Citizen, you have access to the &lt;a href=&quot;https://www.dol.gov/agencies/whd/immigration/h1b1&quot;&gt;H-1B1 US visa&lt;/a&gt;, and as a graduate of NUS or NTU, you have access to the &lt;a href=&quot;https://www.gov.uk/high-potential-individual-visa/eligibility&quot;&gt;HPI UK visa&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Including objective metrics of impact. I started quantifying my impact in numbers, focusing on demonstrating the improvements made through my contributions.&lt;/li&gt;
&lt;li&gt;Using ChatGPT to paraphrase bullet points. I would first write a couple of sentences for each bullet point, and then use ChatGPT to summarize and paraphrase the bullet point, tweaking the result. A simple prompt could be, “Can you help to generate a resume bullet point of this contribution? Emphasize the impact of my contribution.”&lt;/li&gt;
&lt;li&gt;Ask for referrals from people you know. It might seem embarrassing, but asking for a referral from people who you have worked with, and can vouch for you, is super helpful in getting a foot in the door.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/evolution-of-resumes/pre-stripe.png&quot; alt=&quot;University year 3&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I have been so fortunate to be where I am today. As much as I would love to claim that all you need is passion, having a support network of friends and seniors, being in the “right place, right time”, and having the privilege and time to work on things I enjoy, have all significantly contributed to my success thus far. If you would like to see a more exhaustive list of my working history, you can check out my &lt;a href=&quot;https://linkedin.com/in/woojiahao&quot;&gt;Linkedin profile&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All the best!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;[1] My reflection on my time in tech: &lt;a href=&quot;/post/ten-years-in-tech&quot;&gt;Ten Years in Tech&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[2] If you are starting the technical interview preparation process or are looking to polish your skills, I have prepared a technical interview study guide with my notes that got me into firms like Citadel, Palantir, and Google: &lt;a href=&quot;https://interviews.woojiahao.com&quot;&gt;Technical Interview Study Guide&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[3] My CVWO web forum project: &lt;a href=&quot;https://github.com/woojiahao/hermes&quot;&gt;hermes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[4] I have moved over to using Typst to generate my resume, but my Google Docs resume template is still available: &lt;a href=&quot;https://docs.google.com/document/d/1mZ6Fz0Dxwxm8dqhY129wnCz1V5bfpxIVv1J2AOqCgu0/edit?usp=sharing&quot;&gt;Jiahao Woo Blank Resume Template&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[5] My Typst template can be found in this Github repository. Use the repository as a template and get started: &lt;a href=&quot;https://github.com/woojiahao/resume-template&quot;&gt;woojiahao/resume-template&lt;/a&gt;&lt;/p&gt;</description><pubDate>Mon, 21 Apr 2025 00:00:00 GMT</pubDate></item><item><title>Reframing Failure</title><link>https://blog.woojiahao.com/post/reframing-failure</link><guid isPermaLink="true">https://blog.woojiahao.com/post/reframing-failure</guid><description>&lt;p&gt;I saw this message on an online forum and it reminded me of the uncertainty I felt before starting every one of my internships.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/reframing-failure/inspiration.jpg&quot; alt=&quot;Inspiration&quot;&gt;&lt;/p&gt;
&lt;p&gt;After sharing some of my sentiments in the forum, it got me thinking about my past experiences and how I’ve started reframing failure in tech and I wanted to consolidate those thoughts here.&lt;/p&gt;
&lt;h2 id=&quot;what-is-failure&quot;&gt;What is failure?&lt;/h2&gt;
&lt;p&gt;Before I dive into how I reframe failure, I think it’s good to set some precedence about what exactly constitutes a failure in tech — specifically during a tech internship.&lt;/p&gt;
&lt;p&gt;To some, failure might look like this…&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/reframing-failure/reddit.png&quot; alt=&quot;Reddit post&quot;&gt;&lt;/p&gt;
&lt;p&gt;And perhaps, incidents like these are the reason why we are so afraid of failures in our own internships.&lt;/p&gt;
&lt;p&gt;To me, another mode of failure I often worry about is not being able to complete a feature on time or even finishing the internship project on time.&lt;/p&gt;
&lt;p&gt;Broadly speaking, I think of failure as not being able to live up to the expectations that others might have of us — be it not destroying production or not being able to deliver something.&lt;/p&gt;
&lt;h2 id=&quot;its-okay-to-be-scared&quot;&gt;It’s okay to be scared&lt;/h2&gt;
&lt;p&gt;The most important step in all of this is acknowledging that this fear of screwing up is valid, normal, and very human. Everyone is susceptible to worrying about the unknown.&lt;/p&gt;
&lt;p&gt;It is in our nature to be worriers — after all, if we worry and imagine every possible scenario where we screw up, maybe we could would be ready for when it happens and combat it right?&lt;/p&gt;
&lt;p&gt;Absolutely not. Although it may be in our nature to worry about the what-ifs, it is unproductive to be paralyzed by the fear of the unknowns and what-ifs.&lt;/p&gt;
&lt;p&gt;This is why acknowledging this fear is step 0 — just being aware of it does not fix the problem, but it allows you to see that a problem exists. Only then can you start working towards addressing it.&lt;/p&gt;
&lt;h2 id=&quot;if-not-now-then-when&quot;&gt;If not now, then when?&lt;/h2&gt;
&lt;p&gt;Internships are the PERFECT environment for you to learn and grow and fail. You are supposed to be inexperienced, and you are supposed to stumble around. It is all a part of the process, so embrace it.&lt;/p&gt;
&lt;p&gt;While there are many reasons why you are doing the internship, I want to highlight what I believe are the three key purposes of an internship:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Learning opportunity&lt;/li&gt;
&lt;li&gt;Exploring a field&lt;/li&gt;
&lt;li&gt;Meeting and learning from professionals&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Whenever you feel lost and hopeless, remind yourself that you are in the best position to be feeling this way, and turn to the three purposes to figure out what you should be prioritizing. Use them as your North Star throughout the experience.&lt;/p&gt;
&lt;h2 id=&quot;self-imposed-expectations-are-not-always-reality&quot;&gt;Self-imposed expectations are not always reality&lt;/h2&gt;
&lt;p&gt;It is easy to feel like you have to produce the best code, write the best documentation, generate the most value, and deliver the most impact.  However, take a step back and ask yourself, “Are these actually what is expected of me? Or are these just what I believe I should be doing?”&lt;/p&gt;
&lt;p&gt;As the intern, you are NOT expected to be perfect. Heck, even as a junior/senior engineer, no one expects perfection out of you. No sensible person would place such unrealistic expectations on others, which begs the question — why do you place such unrealistic expectations on yourself?&lt;/p&gt;
&lt;p&gt;Be conscious about your self-imposed expectations and realize that the world does not demand perfection from you, you do. So be kind to yourself and allow yourself to make mistakes.&lt;/p&gt;
&lt;h2 id=&quot;perfection-requires-practice-practice-entails-failure&quot;&gt;Perfection requires practice, practice entails failure&lt;/h2&gt;
&lt;p&gt;Let’s suppose that you do want to be perfect and become amazing at what you do. The only way you could even achieve perfection and mastery is through repeated practice which naturally invites failure.&lt;/p&gt;
&lt;p&gt;Some of the very best in their craft achieved their mastery through hundreds and thousands of hours of practice and failures.&lt;/p&gt;
&lt;p&gt;So, rather than shrinking in fear of failure, embrace it and treat them as roadbumps on your road to mastery. Grow to fill your potential, and you will learn to enjoy the process of failing.&lt;/p&gt;
&lt;h2 id=&quot;failure--learning&quot;&gt;Failure == learning&lt;/h2&gt;
&lt;p&gt;The best learning opportunities often arise from the greatest failures. I know that the times where I had the greatest delta in learning were born from hours — if not days — of head scratching and banging my head against a wall trying to get something working but failing repeatedly.&lt;/p&gt;
&lt;p&gt;The process might be brutal and it might suck in the moment, but more often than not, these are the points where you get to learn and grow the most. In fact, I would argue that if you are not experiencing failure, you are simply not moving out of your comfort zone. So, use these moments as motivations to push through the suffering, knowing that you will grow so much at the end of it.&lt;/p&gt;
&lt;h2 id=&quot;adopting-a-so-what-can-i-do-attitude&quot;&gt;Adopting a “so what can I do” attitude&lt;/h2&gt;
&lt;p&gt;If, and when, you do encounter a roadblock, ask yourself this very simple phrase, “So what can I do?”. Rather than worrying about the consequences of a failure that may or may not materialize, focus your efforts on figuring out what’s the next steps you can do to improve the situation.&lt;/p&gt;
&lt;p&gt;During one of my production incidents, I felt a flurry of emotions that went from:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Oh no&lt;/li&gt;
&lt;li&gt;What did I do?&lt;/li&gt;
&lt;li&gt;*Panics*&lt;/li&gt;
&lt;li&gt;Okay, what can I do?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Going to my mentor, I wanted to fix the problem I had started and it became an opportunity for me to understand how our production systems worked, and how such issues were recalled and fixed. It proved to be a positive learning experience.&lt;/p&gt;
&lt;p&gt;So as difficult as it may feel to face a problem you caused, there can be much to learn from such an experience.&lt;/p&gt;
&lt;h2 id=&quot;trust-in-the-safety-nets&quot;&gt;Trust in the safety nets&lt;/h2&gt;
&lt;p&gt;While I have been talking a lot about how you can reframe failure in YOUR eyes, a big part of reframing and embracing failure is realizing that there exists some set of safety nets for you to fail safely.&lt;/p&gt;
&lt;p&gt;Most companies with decent engineering cultures should have some form of guardrails for you to fail. Having things like proper sandboxed or staging environments, robust CI/CD, comprehensive tests, frequent backups, and detailed rollback plans should give you confidence in being able to fail as much as you want, knowing that these failures do not result in immediate and permanent damage.&lt;/p&gt;
&lt;p&gt;Beyond the engineering capacity of the company, you should trust in your coworkers/mentors/managers/seniors to “have your back” and rally around you to fix your mistakes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/reframing-failure/rally.jpg&quot; alt=&quot;Rallying&quot;&gt;&lt;/p&gt;
&lt;p&gt;These safety nets (or support structures) are quintessential. Knowing that your failures will not cause systems to end up in flames reduces the stress you feel from every mistake and allows you to focus on trying and learning as much.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Failing is scary. Screwing up is horrifying. But doing nothing because of these fears should scare you even more. You need to embrace failure and reframe how you think about failure to be the best version of yourself.&lt;/p&gt;
&lt;p&gt;All the best!&lt;/p&gt;</description><pubDate>Sat, 15 Mar 2025 00:00:00 GMT</pubDate></item><item><title>Ten Years in Tech</title><link>https://blog.woojiahao.com/post/ten-years-in-tech</link><guid isPermaLink="true">https://blog.woojiahao.com/post/ten-years-in-tech</guid><description>&lt;p&gt;2025 marks my tenth year in tech. 15 year old me would not have imagined that 25 year old me would be having so much fun
with a random hobby he picked up but here I am, pursuing tech as a career!&lt;/p&gt;
&lt;p&gt;To mark ten years in tech, I thought it would be fun to document my journey in tech so far. I also wanted to point out the amount of “failures” I received throughout my ten year journey, to serve as a reminder that everyone starts somewhere and getting started it always the hardest step.&lt;/p&gt;
&lt;h2 id=&quot;secondary-school-2014---2016&quot;&gt;Secondary School: 2014 - 2016&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Got a &lt;a href=&quot;https://en.wikipedia.org/wiki/Samsung_Galaxy_Ace_2&quot;&gt;Samsung Galaxy Ace 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Got into Android ROMs, installing ROMs like &lt;a href=&quot;https://en.wikipedia.org/wiki/CyanogenMod&quot;&gt;Cyanogenmod&lt;/a&gt; and
&lt;a href=&quot;https://www.reddit.com/r/Android/comments/18ni90y/its_the_sad_end_of_custom_roms_on_xiaomi_devices/&quot;&gt;MIUI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Started lurking in &lt;a href=&quot;https://xdaforums.com/&quot;&gt;XDA forums&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Decided to (try) learn Android development from a YouTube series by &lt;a href=&quot;https://www.youtube.com/@xda/videos&quot;&gt;xda-developers&lt;/a&gt; (I couldn’t find the series anymore 😔)&lt;/li&gt;
&lt;li&gt;Did not really understand Android development and gave up (Failure #1)&lt;/li&gt;
&lt;li&gt;Printed out &lt;a href=&quot;https://www.javatpoint.com/java-tutorial&quot;&gt;tutorials on Java&lt;/a&gt; and trying to learn Java (yes, I printed them out and bound it)&lt;/li&gt;
&lt;li&gt;Did not enjoy learning Java too much and gave up again (Failure #2)&lt;/li&gt;
&lt;li&gt;Wanted to find the “perfect language” to start programming&lt;/li&gt;
&lt;li&gt;Visited the
&lt;a href=&quot;https://www.nlb.gov.sg/main/visit-us/our-libraries-and-locations/libraries/yishun-public-library&quot;&gt;public library&lt;/a&gt; many times
to borrow books on programming like &lt;a href=&quot;https://www.dummies.com/book/technology/programming-web-design/csharp/c-2010-all-in-one-for-dummies-292899/&quot;&gt;C#&lt;/a&gt; and &lt;a href=&quot;https://www.amazon.sg/HTML-CSS-Design-Build-Websites/dp/1118008189&quot;&gt;web development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Tried setting up the family computer (&lt;a href=&quot;https://en.wikipedia.org/wiki/Dynabook_Satellite&quot;&gt;Toshiba Satellite&lt;/a&gt;) to dual boot &lt;a href=&quot;https://ubuntu.com/&quot;&gt;Ubuntu&lt;/a&gt; and Windows&lt;/li&gt;
&lt;li&gt;Accidentally wiped the Windows partition instead 🤡 (Failure #3)&lt;/li&gt;
&lt;li&gt;Discovered &lt;a href=&quot;https://youtu.be/Dv7gLpW91DM?si=8Vdb2-jIO8e-PuRc&quot;&gt;a video about why programming is important&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;display: flex; align-items: center; justify-content: center;&quot;&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/Dv7gLpW91DM?si=XxNhtLYaQUAFNiGE&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Ignited a deeper interest in me to learn more about it and treat it as a fun hobby and find a wider community to enjoy it with&lt;/li&gt;
&lt;li&gt;Dad brought me to &lt;a href=&quot;https://en.wikipedia.org/wiki/Bras_Basah&quot;&gt;Bras Basah&lt;/a&gt; to browse second-hand bookstores&lt;/li&gt;
&lt;li&gt;Got books about &lt;a href=&quot;https://www.amazon.sg/Absolute-C-Walter-Savitch/dp/0133970787&quot;&gt;C++&lt;/a&gt; and &lt;a href=&quot;https://www.amazon.com/iOS-Programmers-App-Driven-Approach-Developer/dp/0133965260&quot;&gt;iOS development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Installed &lt;a href=&quot;https://visualstudio.microsoft.com/&quot;&gt;Visual Studio&lt;/a&gt; to learn C++&lt;/li&gt;
&lt;li&gt;Did not have an Apple machine to learn iOS development (yes, the book became useless) (Failure #4)&lt;/li&gt;
&lt;li&gt;Started picking up C++ and understanding the fundamentals of programming&lt;/li&gt;
&lt;li&gt;But really struggled with understanding pointers (who doesn’t on their first attempt) (Failure #5)&lt;/li&gt;
&lt;li&gt;Took the &lt;a href=&quot;https://en.wikipedia.org/wiki/Singapore-Cambridge_GCE_Ordinary_Level&quot;&gt;O-Levels&lt;/a&gt; and did really well (L1R4 of 4 and L1R5 of 6)&lt;/li&gt;
&lt;li&gt;Faced with making a tricky decision of choosing &lt;a href=&quot;https://en.wikipedia.org/wiki/Junior_college_(Singapore)&quot;&gt;Junior College&lt;/a&gt; or &lt;a href=&quot;https://en.wikipedia.org/wiki/Institute_of_technology&quot;&gt;Polytechnic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Unsure if I should study chemical engineering or information technology&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/post/ten-years-in-tech/school_choices.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Took a leap of faith and decided to pursue my interest in tech by studying IT at &lt;a href=&quot;https://sopossible.sp.edu.sg/courses/schools/soc/information-technology&quot;&gt;Singapore Polytechnic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;polytechnic-2017---2020&quot;&gt;Polytechnic: 2017 - 2020&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Started my diploma in Information Technology!&lt;/li&gt;
&lt;li&gt;Started learning Java as my first language in school from &lt;a href=&quot;https://www.youtube.com/watch?v=TBWX97e1E9g&amp;#x26;list=PLE7E8B7F4856C9B19&quot;&gt;Derek Banas&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;display: flex; align-items: center; justify-content: center;&quot;&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/TBWX97e1E9g?si=oleCVTG_yaCNxLHR&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Built my very first &lt;a href=&quot;https://github.com/woojiahao/chat-bot&quot;&gt;proper project&lt;/a&gt; for school (a chat bot!)&lt;/li&gt;
&lt;li&gt;Joined &lt;a href=&quot;https://theprogrammershangout.com/&quot;&gt;The Programmers Hangout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Met an amazing community of people who were equally passionate about tech&lt;/li&gt;
&lt;li&gt;Became a moderator on the server and continued making friends from around the world&lt;/li&gt;
&lt;li&gt;Started side projects to explore different technologies like Kotlin like a &lt;a href=&quot;https://github.com/woojiahao/taiga&quot;&gt;Discord moderation bot&lt;/a&gt;, &lt;a href=&quot;https://github.com/woojiahao/java-spotify-wrapper&quot;&gt;Spotify API wrapper&lt;/a&gt;, and &lt;a href=&quot;https://github.com/omnius-project/kMD2PDF&quot;&gt;extensible Markdown to PDF conversion library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Introduced to &lt;a href=&quot;https://e27.co/startups/mightyaim/&quot;&gt;MightyAim&lt;/a&gt; by a friend&lt;/li&gt;
&lt;li&gt;Working at MightyAim for a while as an Android developer, building an SDK to allow existing applications to adopt a gesture-based workflow&lt;/li&gt;
&lt;li&gt;Received my first paycheck (of SGD 300!)&lt;/li&gt;
&lt;li&gt;Went back to Bras Basah to buy books on algorithms and operating systems with my newfound wealth 🤑&lt;/li&gt;
&lt;li&gt;Attended &lt;a href=&quot;https://2018.phpconf.asia/&quot;&gt;PHP Conference Asia 2018&lt;/a&gt; even though I didn’t know PHP (and still don’t)&lt;/li&gt;
&lt;li&gt;Invited to teach a workshop for students over the semester break&lt;/li&gt;
&lt;li&gt;Put together &lt;a href=&quot;https://woojiahao.com/KotlinToDo/#/&quot;&gt;“Introduction to Android Development with Kotlin”&lt;/a&gt; and taught over 15 students live!&lt;/li&gt;
&lt;li&gt;Discovered my love for teaching and writing through this experience&lt;/li&gt;
&lt;li&gt;Started my &lt;a href=&quot;https://github.com/woojiahao/woojiahao.github.io/tree/master&quot;&gt;blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Got placed to &lt;a href=&quot;https://www.dbs.com.sg/private-banking/default.page&quot;&gt;DBS Bank&lt;/a&gt; for my polytechnic internship under the SOI Re-platform team&lt;/li&gt;
&lt;li&gt;Worked across teams to get 90% UAT completion (across over 90 teams) and did a bunch of root cause analysis&lt;/li&gt;
&lt;li&gt;Attached to &lt;a href=&quot;https://www.linkedin.com/company/rebeehealth/posts/?feedView=all&quot;&gt;XCLR8&lt;/a&gt; for my Final Year Project&lt;/li&gt;
&lt;li&gt;Migrated the backend from Java to Kotlin Spring Boot and the database from MongoDB to PostgreSQL&lt;/li&gt;
&lt;li&gt;Became valedictorian of my cohort! Graduating with a 4.0 out of 4.0 GPA&lt;/li&gt;
&lt;li&gt;Still felt like I wanted to find my tribe in person&lt;/li&gt;
&lt;li&gt;Was rejected from the &lt;a href=&quot;https://www.psc.gov.sg/scholarships&quot;&gt;PSC Scholarship&lt;/a&gt; (Failure #6)&lt;/li&gt;
&lt;li&gt;Got accepted into &lt;a href=&quot;https://www.comp.nus.edu.sg/programmes/ug/cs/&quot;&gt;NUS Computer Science&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Started a research internship with &lt;a href=&quot;https://www.dso.org.sg/&quot;&gt;DSO National Laboratories&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Integrated social media information for unsupervised stance detection and was exposed to NLP research!&lt;/li&gt;
&lt;li&gt;Enlisted in the &lt;a href=&quot;https://sso.agc.gov.sg/Act/EA1970&quot;&gt;Singapore military&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;national-service-2020---2022&quot;&gt;National Service: 2020 - 2022&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Focused on &lt;a href=&quot;https://blog.woojiahao.com&quot;&gt;technical writing&lt;/a&gt; instead&lt;/li&gt;
&lt;li&gt;Got really into Elixir through &lt;a href=&quot;https://github.com/woojiahao/Advent-of-code-2020&quot;&gt;2020 Advent of Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Started writing about &lt;a href=&quot;https://blog.woojiahao.com/post/odd-hound/&quot;&gt;Elixir on my blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Invited to write for company blogs&lt;/li&gt;
&lt;li&gt;Got articles featured on Elixir newsletters&lt;/li&gt;
&lt;li&gt;Studied &lt;a href=&quot;https://www.pearson.com/en-us/subject-catalog/p/thomas-calculus/P200000007103/9780137616077&quot;&gt;calculus&lt;/a&gt; in my free time to prepare for university&lt;/li&gt;
&lt;li&gt;Applied to US universities like MIT and Stanford for Computer Science&lt;/li&gt;
&lt;li&gt;Got rejected by every US university (Failure #7)&lt;/li&gt;
&lt;li&gt;Built &lt;a href=&quot;https://github.com/woojiahao/chris&quot;&gt;&lt;code&gt;chris&lt;/code&gt;&lt;/a&gt;, a &lt;a href=&quot;https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html&quot;&gt;Pratt parser&lt;/a&gt; written in Go&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chris&lt;/code&gt; was featured on the &lt;a href=&quot;https://golangweekly.com/&quot;&gt;Golang Weekly newsletter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;university-2022---now&quot;&gt;University: 2022 - Now&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Enrolled in the National University of Singapore’s School of Computing, studying Computer Science&lt;/li&gt;
&lt;li&gt;Joined &lt;a href=&quot;https://rc4.nus.edu.sg/&quot;&gt;Residential College 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Met many close friends in RC4&lt;/li&gt;
&lt;li&gt;Joined &lt;a href=&quot;https://dscnustech.github.io/&quot;&gt;NUS Google Developer Student Club&lt;/a&gt; as a backend software engineer on Project Sight Word&lt;/li&gt;
&lt;li&gt;Met more amazing friends from GDSC&lt;/li&gt;
&lt;li&gt;Realized I was not cut out to be an academic weapon after struggling in my first semester (Failure #8)&lt;/li&gt;
&lt;li&gt;Realized that getting a job in tech was very hard after flunking a bunch of technical interviews (Failure #9)&lt;/li&gt;
&lt;li&gt;Discovered the existence of Leetcode&lt;/li&gt;
&lt;li&gt;Joined &lt;a href=&quot;https://nushackers.org&quot;&gt;NUS Hackers&lt;/a&gt; and finally discovered my tribe IRL&lt;/li&gt;
&lt;li&gt;Articles were noticed by &lt;a href=&quot;https://www.linkedin.com/in/sherbondy/&quot;&gt;Ethan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ethan offered for me to do an internship at &lt;a href=&quot;https://www.betafi.co/&quot;&gt;Betafi&lt;/a&gt; using Elixir + Phoenix!&lt;/li&gt;
&lt;li&gt;Joined Betafi as a software engineer intern and worked on improving the video processing pipeline and adding project templates&lt;/li&gt;
&lt;li&gt;Started the &lt;a href=&quot;https://interviews.woojiahao.com&quot;&gt;Technical Interview Study Guide&lt;/a&gt; to compile my notes from interview preparations&lt;/li&gt;
&lt;li&gt;Taught a workshop on Git and another on databases for &lt;a href=&quot;https://nusmods.com/courses/CP2106/independent-software-development-project-orbital&quot;&gt;Orbital&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Became the top student for &lt;a href=&quot;https://nusmods.com/courses/CS2103/software-engineering&quot;&gt;CS2103/T (Software Engineering)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Returned to CS2103/T as a teaching assistant (and got 4.8/5.0 for teaching feedback!)&lt;/li&gt;
&lt;li&gt;Taught a &lt;a href=&quot;https://www.youtube.com/watch?v=-VHBMXxCee0&quot;&gt;web development with Elixir workshop for Hackerschool&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;display: flex; align-items: center; justify-content: center;&quot;&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/-VHBMXxCee0?si=-wuWkg8zi-ssjw2N&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Taught another workshop on Git for Hackerschool&lt;/li&gt;
&lt;li&gt;Got internship offers from Google, Citadel, Palantir, and PayPal!&lt;/li&gt;
&lt;li&gt;Organized Hack&amp;#x26;Roll 2024, supporting the web app used by over 800 live participants and 40 organizers&lt;/li&gt;
&lt;li&gt;Realized on-call isn’t fun and that the web app had to be rewritten to be more intuitive (Failure #10)&lt;/li&gt;
&lt;li&gt;Taught yet another workshop on Git for Orbital (again)&lt;/li&gt;
&lt;li&gt;Joined Citadel as a site reliability engineer intern over the summer on the Central SRE team&lt;/li&gt;
&lt;li&gt;Met an amazing team and mentor, Nelson&lt;/li&gt;
&lt;li&gt;Worked on preparing the Commodities Observability Platform for a disaster recovery exercise and implementing an automated incident post-mortem tool&lt;/li&gt;
&lt;li&gt;Flew off to London immediately after to join Palantir as a software engineer intern on the Developer Console team&lt;/li&gt;
&lt;li&gt;Met awesome people both within the Dev Console team (shoutout to Zeyad, Amish, Nadira, Xinyi, and Tim!) and outside of the team, creating amazing memories in London&lt;/li&gt;
&lt;li&gt;Integrated Platform API support into Ontology SDK clients and made many memes&lt;/li&gt;
&lt;li&gt;Working intensely towards getting the rewritten web app out (and I did!)&lt;/li&gt;
&lt;li&gt;Returning to school!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Wow! That took a while to recap! It has been such a wonderful journey and I am so happy that 15 year old me decided to get into tech. I got to meet so many amazing people and work on so many interesting problems.&lt;/p&gt;
&lt;p&gt;Although I have had many successes as well, I have faced many failures as well (10 in total!) and these failures have taught me so much. The past ten years has been so fun and I can’t wait to see what the next 10 years has in store for me! 🎉&lt;/p&gt;</description><pubDate>Wed, 08 Jan 2025 00:00:00 GMT</pubDate></item><item><title>Maximizing learning at internships</title><link>https://blog.woojiahao.com/post/maximizing-learning-at-internships</link><guid isPermaLink="true">https://blog.woojiahao.com/post/maximizing-learning-at-internships</guid><description>&lt;p&gt;“Congratulations! XYZ company would love to extend an offer to you for the summer! Please find the offer letter attached!”&lt;/p&gt;
&lt;p&gt;The dopamine rush from finally seeing your efforts pay off is unbeatable! After going through countless rounds of interviews with recruiters, engineers, and hiring managers, you finally have a foot into XYZ!&lt;/p&gt;
&lt;p&gt;However, as you start the internship, you quickly realize that getting in was step 0. The real battle starts here and now you are wondering how you are going to maximize your three-months as an intern. I will attempt to share the insights that I have gained throughout my internship experiences and focus on answering four fundamental questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How do I ask questions?&lt;/li&gt;
&lt;li&gt;How do I navigate the complex codebases?&lt;/li&gt;
&lt;li&gt;How do I understand the overall product easily?&lt;/li&gt;
&lt;li&gt;How do I contribute to the projects?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;P.S. If you just want a TL;DR of the advice as bullet points, find them &lt;a href=&quot;#tips-at-a-glance&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;asking-questions&quot;&gt;Asking questions&lt;/h1&gt;
&lt;p&gt;Just like raising your hand in class to ask a question, going to someone in a new environment to ask seemingly silly questions can feel like a daunting task. But as with anything new, the first step is always the hardest. These are some tips to help you figure out the best way to phrase and ask questions to maximize your takeaway.&lt;/p&gt;
&lt;h2 id=&quot;compile-questions&quot;&gt;Compile questions&lt;/h2&gt;
&lt;p&gt;As you are reading through the codebase or using the product, keep a document/notebook/napkin of questions you have in mind and try connecting the dots as you go through the system(s). Cross out questions you figured out the answers for and highlight those that you need help with. This helps collect your thoughts and tracks important questions to ask, ensuring that you fully grasp the system.&lt;/p&gt;
&lt;h2 id=&quot;research-beforehand&quot;&gt;Research beforehand&lt;/h2&gt;
&lt;p&gt;Perform preliminary research as you compile your questions. Here is a hypothetical: would you rather have to explain a concept to someone who has no idea what is going on? Or would you rather have a discussion about the concept with this person who is actively clarifying their understanding with you? I am sure everyone would much rather do the second so do to others what you would have them do to you.&lt;/p&gt;
&lt;h2 id=&quot;pay-attention-and-ask-follow-up-questions&quot;&gt;Pay attention and ask follow-up questions&lt;/h2&gt;
&lt;p&gt;As someone is answering your questions, pay attention and think of any follow-up questions you might have. Try connecting the explanation to your understanding of the other systems and think about whether this new information supports or contradicts what you know already. Ask follow-up questions based on this and ensure that you leave the session with a better understanding than before.&lt;/p&gt;
&lt;h2 id=&quot;just-ask&quot;&gt;Just ask&lt;/h2&gt;
&lt;p&gt;Do not wait for the perfect opportunity to ask a question, it does not exist. It is not 3 hours later, it is not a day later. It is as soon as you realize that you are going nowhere with your own research and efforts. Once you have hit the brick wall, you should ask the people around you for help. If you do not know when you have hit the brick wall, a rule of thumb I have is that if I have made no concrete progress in 30 minutes, it is time to ask someone for help. Keeping your questions to yourself will only harm your learning.&lt;/p&gt;
&lt;h1 id=&quot;navigating-complex-codebases&quot;&gt;Navigating complex codebases&lt;/h1&gt;
&lt;p&gt;No matter where you go, there is a 90% chance you end up having to comb through a relatively complex codebase. As opposed to working on side projects or school work, you will rarely be creating new systems from scratch. So learning to navigate a complex codebase is a crucial skill to learn.&lt;/p&gt;
&lt;h2 id=&quot;use-search-tools&quot;&gt;Use search tools&lt;/h2&gt;
&lt;p&gt;Search tools like &lt;a href=&quot;https://sourcegraph.com/&quot;&gt;SourceGraph&lt;/a&gt; are amazing ways of searching across repositories. If your organization does not use SourceGraph, GitHub’s built-in search functionality works well too. Even a simple &lt;code&gt;grep&lt;/code&gt; command can be leveraged to navigate through the codebase quickly! Understanding these search tools can be key in getting the relevant code in front of you as soon as possible.&lt;/p&gt;
&lt;h2 id=&quot;search-and-trace-smartly&quot;&gt;Search and trace smartly&lt;/h2&gt;
&lt;p&gt;Knowing WHAT to search for is as important as having good search tool. For instance, if you are looking at a front-end project and want to make changes to a page, the fastest way to figure out what file the page belongs to is by looking up words on the page. For back-end projects, you may want to use tools like “Jump to implementation/references” to figure out what are the parent classes and definitions. There are many ways to search smartly and navigate a complex codebase, so the best way is to figure out what a good starting point is and go from there.&lt;/p&gt;
&lt;h2 id=&quot;read-other-codebases&quot;&gt;Read other codebases&lt;/h2&gt;
&lt;p&gt;While it may seem like self-inflicted torture, getting good at navigating complex codebases is a learned skill and the best way to train that skill is to read other codebases. Whether it is other services within your organization or open-source projects, you can only get good at understanding code by reading code. One thing I did a few years ago was to analyse open-source Elixir projects, take detailed notes, and &lt;a href=&quot;https://blog.woojiahao.com/post/odd-broadway-1/&quot;&gt;write blog posts about them&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;understand-underlying-libraries-and-tools&quot;&gt;Understand underlying libraries and tools&lt;/h2&gt;
&lt;p&gt;It is very easy to treat underlying libraries and tools as blackboxes. However, this mental model of systems is usually unsustainable in the long term. So it is usually better to treat the underlying libraries as though they are part of your projects and delve deep when and where you can. This way, when you are faced with a random error thrown from a dependency, you will not be stuck staring at the stack trace. The same goes for the tools you are using, whether it’s your IDE or logging tools like Grafana Loki or CI/CD tools. Knowing the tools you use well ensures that you do not get stuck the moment something in the background stops working.&lt;/p&gt;
&lt;h2 id=&quot;organize-teach-back-sessions&quot;&gt;Organize teach back sessions&lt;/h2&gt;
&lt;p&gt;You have amassed all of this new knowledge, that’s awesome! But are you sure that you have fully understood the systems? This is why teach back sessions are amazing, they give you the platform to share your knowledge with others. Yes, it is going to be scary presenting your potentially flawed ideas to the “experts” but remember: everyone is there to see you succeed, not to see you fail. Having these “experts” listening to your interpretation of the system can boost your confidence and if you are mistaken, you have access to immediate feedback and correction. It is a win-win! So put some time on your team’s calendar and present your findings to them!&lt;/p&gt;
&lt;h2 id=&quot;start-with-low-hanging-issues&quot;&gt;Start with low-hanging issues&lt;/h2&gt;
&lt;p&gt;If your team labels their issues with &lt;code&gt;good first issue&lt;/code&gt; (or something equivalent), focus on knocking those out first. Try to solve at least one a day (this is not a hard rule, just something that I try to achieve to ensure that I have a healthy pace of learning) and pick the ones that allow you to work across all the core platforms that your team manages. They might feel like menial tasks, but they are essential in wetting your feet and giving you confidence! If you are lost on where to start or if you are going in the right direction, ASK!&lt;/p&gt;
&lt;h1 id=&quot;contributing-to-codebases&quot;&gt;Contributing to codebases&lt;/h1&gt;
&lt;p&gt;Now that you have understood how to navigate a complex codebase, the tricky part is actually contributing code to it! Try out these tips to maximize your contributions.&lt;/p&gt;
&lt;h2 id=&quot;start-small&quot;&gt;Start small&lt;/h2&gt;
&lt;p&gt;Building on top of &lt;a href=&quot;#start-with-low-hanging-issues&quot;&gt;“Start with low-hanging issues”&lt;/a&gt;, you should start with small issues and work your way up. Starting small also applies to the types of changes you are making. Focus on making small changes to one affected area at a time and moving to the next. So start by breaking down the problem into smaller parts and focus on solving them individually until you have managed to fix the problem or add the feature!&lt;/p&gt;
&lt;h2 id=&quot;use-existing-prs-as-reference&quot;&gt;Use existing PRs as reference&lt;/h2&gt;
&lt;p&gt;No, it is not cheating! You do not need to come up with the solutions all on your own and bang your head against the wall trying to work with a foreign system! A big benefit of working in a team and working on a developed codebase is having fallbacks and references in the form of other people’s code! So leverage this advantage and use existing PRs as reference when writing your code! Not only will it help you get over the hurdle of “This task feels too big”, it can also save you a ton of time re-inventing what others have thought of and done. Additionally, existing PRs set precedence on the best practices and structure of codebases and it is always best to follow (and sometimes question) these practices.&lt;/p&gt;
&lt;h2 id=&quot;git-blame-excessively&quot;&gt;Git blame excessively&lt;/h2&gt;
&lt;p&gt;While &lt;a href=&quot;https://git-scm.com/docs/git-blame&quot;&gt;Git blame&lt;/a&gt; can be used to, well, blame people for making changes that might have broken production, it can also be an invaluable tool when contributing to a codebase because you now can (nicely) approach the latest editor to figure out their rationale of things. There have been many times where the decisions for code felt confusing and I was itching to fix it, but through Git blame and speaking to the last editor, I was able to understand the rationale and (a) identify new issues, (b) learn something new, or (c) work with them to streamline the code.&lt;/p&gt;
&lt;h2 id=&quot;review-your-own-code&quot;&gt;Review your own code&lt;/h2&gt;
&lt;p&gt;When you create your PRs, do not just create a giant essay for the PR description. Invest time into using the “Files” panel (or equivalent) to review your changes. Use GitHub’s “Viewed” to methodically check off files you have reviewed yourself. Add comments about questions you had about the code, rationales behind the code you have written, follow-ups, descriptions, and more. Think about the code you have written and try to identify code smell that you may have introduced. Test your changes and try to break your feature. These help to criticalensure that you are producing the best possible code, giving clarity to actual reviewers, and ultimately, training you to critically analyze your own code effectively.&lt;/p&gt;
&lt;h2 id=&quot;get-frequent-feedback&quot;&gt;Get frequent feedback&lt;/h2&gt;
&lt;p&gt;It is easy to feel like your changes should be perfect on the first go to avoid having back and forth with reviewers. But that is a very flawed way of viewing code reviews. Code reviews are built to review your code (seems silly to explain it but it is important to remind yourself from time to time). It gives you the opportunity to get other people’s eyes on your changes to ensure that they are sensible. So, rather than spending time trying to create the perfect PR, create the PR, &lt;a href=&quot;#review-your-own-code&quot;&gt;review your own code&lt;/a&gt;, and open the floodgates for comments. Iterate on the feedback quickly and ask questions about the comments. This allows you to work closer with your team and helps accelerate your pace of work!&lt;/p&gt;
&lt;h1 id=&quot;understanding-the-overall-product&quot;&gt;Understanding the overall product&lt;/h1&gt;
&lt;p&gt;Being a software engineer is not all about producing the most amount of code or reviewing the most number of PRs. It is also about understanding the product that your company is building and how your team and your work fits into the bigger picture. Knowing all of this helps you to think about the “What’s next?”.&lt;/p&gt;
&lt;h2 id=&quot;treat-the-product-like-an-end-user&quot;&gt;Treat the product like an end user&lt;/h2&gt;
&lt;p&gt;The easiest way to understand a product is to be a consumer. Approach it with skepticism and play around with the features that the product has. Come up with use cases and use the product to solve them. Use these opportunities to pinpoint flaws in the product and identify core pain points. This process is commonly known as “&lt;a href=&quot;https://en.wikipedia.org/wiki/Eating_your_own_dog_food&quot;&gt;Dogfooding&lt;/a&gt;” and it is crucial in giving you insight into how your end users approach your software. It is not easy pretending to be the end user if you know all of the quirks of your own system, but perhaps those quirks are signals into making use case paths clearer or improving some feature.&lt;/p&gt;
&lt;h2 id=&quot;look-for-corner-cases&quot;&gt;Look for corner cases&lt;/h2&gt;
&lt;p&gt;While &lt;a href=&quot;#treat-the-product-like-an-end-user&quot;&gt;dogfooding&lt;/a&gt; or running your changes, always think about “What if I tried this?” and act on it. Look for corner cases in your feature and see if it has been built to handle these cases. Similar to dogfooding, this explicit chasing of corner cases will help in highlighting critical paths that may not have been accounted for and this gives you critical “What’s next?” signals.&lt;/p&gt;
&lt;h2 id=&quot;talk-to-teams-who-own-features-or-services&quot;&gt;Talk to teams who own features or services&lt;/h2&gt;
&lt;p&gt;The world is much bigger than your team and your impact within the team. Speak to teams of other features and services to understand how their features work. Ask about the decisions that have gone into shaping the software and think about how their work fits into the overall product that the company builds. These conversations are great ways to meet more people and understand more systems. They may also uncover potential collaboration between teams, where you discover that your work can be intersected with theirs to create even better user experiences.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Securing internships are hard so do not let all of that effort go to waste by not learning as much as you can. You should be a sponge and use every opportunity to learn and grow as an engineer.&lt;/p&gt;
&lt;p&gt;All the best with your internships!&lt;/p&gt;
&lt;h1 id=&quot;tips-at-a-glance&quot;&gt;Tips at a glance&lt;/h1&gt;
&lt;p&gt;These are the tips at a glance:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Asking questions
&lt;ol&gt;
&lt;li&gt;Compile questions&lt;/li&gt;
&lt;li&gt;Research beforehand&lt;/li&gt;
&lt;li&gt;Pay attention and ask follow-up questions&lt;/li&gt;
&lt;li&gt;Just ask&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Navigating complex codebases
&lt;ol&gt;
&lt;li&gt;Use search tools like SourceGraph&lt;/li&gt;
&lt;li&gt;Search and trace smartly&lt;/li&gt;
&lt;li&gt;Read other codebases&lt;/li&gt;
&lt;li&gt;Understand underlying libraries and tools&lt;/li&gt;
&lt;li&gt;Organize teach back sessions&lt;/li&gt;
&lt;li&gt;Start with low-hanging issues&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Contributing to codebases
&lt;ol&gt;
&lt;li&gt;Start small&lt;/li&gt;
&lt;li&gt;Use existing PRs as reference&lt;/li&gt;
&lt;li&gt;Git blame excessively&lt;/li&gt;
&lt;li&gt;Review your own code&lt;/li&gt;
&lt;li&gt;Get frequent feedback&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Understanding the overall product
&lt;ol&gt;
&lt;li&gt;Treat the product like an end user&lt;/li&gt;
&lt;li&gt;Look for corner cases&lt;/li&gt;
&lt;li&gt;Talk to teams who own features or services&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;</description><pubDate>Tue, 17 Dec 2024 00:00:00 GMT</pubDate></item><item><title>Appreciating &apos;Largest Rectangle in Histogram&apos;</title><link>https://blog.woojiahao.com/post/appreciating-largest-rectangle-in-histogram</link><guid isPermaLink="true">https://blog.woojiahao.com/post/appreciating-largest-rectangle-in-histogram</guid><description>&lt;h1 id=&quot;problem-statement&quot;&gt;Problem statement&lt;/h1&gt;
&lt;p&gt;The ‘Largest Rectangle in Histogram’ problem is as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Given an array of integers heights representing the histogram’s bar height where the width of each bar is 1, return
the area of the largest rectangle in the histogram.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I love this problem as it provides an amazing introduction to problem solving, more specifically, formalizing proofs of
why algorithms work. Let’s start with an example:&lt;/p&gt;
&lt;p&gt;Let the array of heights be &lt;code&gt;[1, 4, 7, 5, 7]&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/leetcode/largest-rectangle/initial.png&quot; alt=&quot;Initial&quot;&gt;&lt;/p&gt;
&lt;p&gt;The answer is &lt;code&gt;16&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/leetcode/largest-rectangle/answer.png&quot; alt=&quot;Answer&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you have solved this problem before, or just looked at the answer, you may have found it hard to convince yourself
why the algorithm works. Fret not, I am here to &lt;em&gt;try&lt;/em&gt; formalizing the proof of the algorithm so that you can understand
how exactly it works!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The general solution is to keep a monotonically increasing stack of indices&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;invariants&quot;&gt;Invariants&lt;/h1&gt;
&lt;p&gt;We can think of the monotonically increasing property as an invariant that the stack must maintain.&lt;/p&gt;
&lt;p&gt;As a refresher, an &lt;strong&gt;invariant&lt;/strong&gt; is a property that is always true across iterations (of a loop) or for all elements
in a data structure.&lt;/p&gt;
&lt;p&gt;A monotonically increasing stack of indices maintains the following invariants:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c22EF&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;&lt;/li&gt;
&lt;li&gt;&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2264&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2264&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c22EF&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2264&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;notations&quot;&gt;Notations&lt;/h1&gt;
&lt;p&gt;For each index &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2208&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;2&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c29&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; where &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; is the array of heights and &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;. Let &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; be the monotonically increasing
stack.&lt;/p&gt;
&lt;h1 id=&quot;operations&quot;&gt;Operations&lt;/h1&gt;
&lt;p&gt;Many monotonic stack problems involve thinking about two key operations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When to push?&lt;/li&gt;
&lt;li&gt;When to pop?&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;push&quot;&gt;Push&lt;/h2&gt;
&lt;p&gt;When &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; or &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, then we push &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; to the stack as it maintains the invariant.&lt;/p&gt;
&lt;h2 id=&quot;pop&quot;&gt;Pop&lt;/h2&gt;
&lt;p&gt;When &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3E&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; and &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, then we pop from the stack, receiving index &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, and try computing the largest
rectangle &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43F TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; using &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; as the shortest rectangle.&lt;/p&gt;
&lt;p&gt;To calculate the &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43F TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, let &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;. The height of &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43F TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c210E TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;.&lt;/p&gt;
&lt;p&gt;To derive the width of &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43F TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D464 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, we need to find the leftmost and rightmost rectangles that are
still &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;. We can label the indices of these rectangles as &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D459 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; and &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45F TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;.&lt;/p&gt;
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot; display=&quot;true&quot;&gt;&lt;mjx-math display=&quot;true&quot; style=&quot;margin-left: 0; margin-right: 0;&quot; class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D459 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2227&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45F TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;
&lt;p&gt;Otherwise, &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; will no longer be the shortest rectangle. After computing &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43F TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, we can push &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; onto the stack as well.&lt;/p&gt;
&lt;h1 id=&quot;solving&quot;&gt;Solving &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43F TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;&lt;/h1&gt;
&lt;h2 id=&quot;finding-the-rightmost-index&quot;&gt;Finding the rightmost index&lt;/h2&gt;
&lt;p&gt;Notice that if &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; and &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; is monotonically increasing, then &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; must be the rightmost tallest
rectangle. Formally, the claim can be written as&lt;/p&gt;
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot; display=&quot;true&quot;&gt;&lt;mjx-math display=&quot;true&quot; style=&quot;margin-left: 0; margin-right: 0;&quot; class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2200&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2208&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;2&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;2&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;
&lt;p&gt;The above claim implies that &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43F TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; can go from &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; to &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; without encountering a shorter rectangle in between.&lt;/p&gt;
&lt;p&gt;Suppose that &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2203&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2208&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;2&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3A&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, then it must have caused &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; to be popped off of &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; prior
to &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;. However, this causes a contradiction as &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2208&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;. Therefore, the claim holds and as a result, &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D459 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;.&lt;/p&gt;
&lt;h2 id=&quot;finding-the-leftmost-index&quot;&gt;Finding the leftmost index&lt;/h2&gt;
&lt;h3 id=&quot;case-1&quot;&gt;Case 1: &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup space=&quot;3&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;&lt;/h3&gt;
&lt;p&gt;If &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup space=&quot;3&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, then &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; by monotonic stack. Thus, the &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D459 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup space=&quot;4&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; as that implies that the
leftmost rectangle that is &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D459 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; is &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; itself.&lt;/p&gt;
&lt;h3 id=&quot;case-2&quot;&gt;Case 2: &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup space=&quot;3&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3E&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;&lt;/h3&gt;
&lt;p&gt;If &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup space=&quot;3&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3E&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, then what we want to show is that&lt;/p&gt;
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot; display=&quot;true&quot;&gt;&lt;mjx-math display=&quot;true&quot; style=&quot;margin-left: 0; margin-right: 0;&quot; class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2200&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2208&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c28&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.413em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;2&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c29&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;2&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2227&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;
&lt;p&gt;To prove this, notice that &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2200&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2208&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c28&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;2&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c29&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-n&quot; space=&quot;2&quot;&gt;&lt;mjx-c class=&quot;mjx-c2203&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45C TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2208&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c28&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;2&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c29&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3A&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45C TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; given that &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2209&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup space=&quot;4&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;.
Also notice that &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45C TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, otherwise, &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; would not be in &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;. This proves the first part of the
claim where &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; as &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45C TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; can be interchanged with &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;.&lt;/p&gt;
&lt;p&gt;Given that &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45C TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2209&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup space=&quot;4&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; as well (otherwise &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45C TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;), then &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2200&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45C TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2208&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c28&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D458 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;2&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c29&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;2&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45C TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, otherwise,
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45C TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2208&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup space=&quot;4&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; which is a contradiction. That means &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; would have caused the final &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45C TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; to be popped from the stack.&lt;/p&gt;
&lt;p&gt;Therefore, the claim is proven and we know that &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D459 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup space=&quot;4&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; as the leftmost rectangle that is &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D459 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; is
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; given that &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2264&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; by monotonic stack.&lt;/p&gt;
&lt;h3 id=&quot;case-3&quot;&gt;Case 3: &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;&lt;/h3&gt;
&lt;p&gt;If &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;. When this happens there is no leftmost rectangle, so we can set &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D459 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;.&lt;/p&gt;
&lt;h2 id=&quot;calculating&quot;&gt;Calculating &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D464 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;&lt;/h2&gt;
&lt;p&gt;Therefore, we have found both the rightmost index where &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45F TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45F TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; and the leftmost index where
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D459 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c2265&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43B TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D457 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D459 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup space=&quot;4&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; or &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D459 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;. The width of &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D43F TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt; is therefore, &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D464 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D45F TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D459 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;.&lt;/p&gt;
&lt;p&gt;If &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3E&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, then &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D464 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c28&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c29&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c28&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c29&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup space=&quot;3&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c5D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;.&lt;/p&gt;
&lt;p&gt;If &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-msup&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D446 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-script style=&quot;vertical-align: 0.363em; margin-left: 0.052em;&quot;&gt;&lt;mjx-mo class=&quot;mjx-var&quot; size=&quot;s&quot;&gt;&lt;mjx-c class=&quot;mjx-c2032&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;/mjx-script&gt;&lt;/mjx-msup&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c7C&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;, then &lt;mjx-container class=&quot;MathJax&quot; jax=&quot;CHTML&quot;&gt;&lt;mjx-math class=&quot;MJX-TEX&quot;&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D464 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c28&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot;&gt;&lt;mjx-c class=&quot;mjx-c29&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2212&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c30&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c2B&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mn class=&quot;mjx-n&quot; space=&quot;3&quot;&gt;&lt;mjx-c class=&quot;mjx-c31&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mn&gt;&lt;mjx-mo class=&quot;mjx-n&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c3D&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mo&gt;&lt;mjx-mi class=&quot;mjx-i&quot; space=&quot;4&quot;&gt;&lt;mjx-c class=&quot;mjx-c1D456 TEX-I&quot;&gt;&lt;/mjx-c&gt;&lt;/mjx-mi&gt;&lt;/mjx-math&gt;&lt;/mjx-container&gt;.&lt;/p&gt;
&lt;h1 id=&quot;implementation&quot;&gt;Implementation&lt;/h1&gt;
&lt;p&gt;When we implement the algorithm, we see that we naturally derive the ideal stack solution:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; largestRectangleArea&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, heights: List[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]) -&gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    stack &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    heights.append(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    n &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(heights)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ans &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(n):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stack &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; heights[i] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; heights[stack[&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            j &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stack.pop()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            h &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; heights[j]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stack &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stack[&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            ans &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; max&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ans, w &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; h)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        stack.append(i)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ans&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;There you have it! The largest rectangle in histogram algorithm has now been formally proven and the magic numbers have
been answered! Of course, when working on these problems during an interview, it is not expected of you to derive these
proofs from scratch, but having such an intuition about monotonic stacks help a lot in reasoning with the magic values
that are used!&lt;/p&gt;&lt;style&gt;
mjx-container[jax=&quot;CHTML&quot;] {
  line-height: 0;
}

mjx-container [space=&quot;1&quot;] {
  margin-left: .111em;
}

mjx-container [space=&quot;2&quot;] {
  margin-left: .167em;
}

mjx-container [space=&quot;3&quot;] {
  margin-left: .222em;
}

mjx-container [space=&quot;4&quot;] {
  margin-left: .278em;
}

mjx-container [space=&quot;5&quot;] {
  margin-left: .333em;
}

mjx-container [rspace=&quot;1&quot;] {
  margin-right: .111em;
}

mjx-container [rspace=&quot;2&quot;] {
  margin-right: .167em;
}

mjx-container [rspace=&quot;3&quot;] {
  margin-right: .222em;
}

mjx-container [rspace=&quot;4&quot;] {
  margin-right: .278em;
}

mjx-container [rspace=&quot;5&quot;] {
  margin-right: .333em;
}

mjx-container [size=&quot;s&quot;] {
  font-size: 70.7%;
}

mjx-container [size=&quot;ss&quot;] {
  font-size: 50%;
}

mjx-container [size=&quot;Tn&quot;] {
  font-size: 60%;
}

mjx-container [size=&quot;sm&quot;] {
  font-size: 85%;
}

mjx-container [size=&quot;lg&quot;] {
  font-size: 120%;
}

mjx-container [size=&quot;Lg&quot;] {
  font-size: 144%;
}

mjx-container [size=&quot;LG&quot;] {
  font-size: 173%;
}

mjx-container [size=&quot;hg&quot;] {
  font-size: 207%;
}

mjx-container [size=&quot;HG&quot;] {
  font-size: 249%;
}

mjx-container [width=&quot;full&quot;] {
  width: 100%;
}

mjx-box {
  display: inline-block;
}

mjx-block {
  display: block;
}

mjx-itable {
  display: inline-table;
}

mjx-row {
  display: table-row;
}

mjx-row &gt; * {
  display: table-cell;
}

mjx-mtext {
  display: inline-block;
}

mjx-mstyle {
  display: inline-block;
}

mjx-merror {
  display: inline-block;
  color: red;
  background-color: yellow;
}

mjx-mphantom {
  visibility: hidden;
}

_::-webkit-full-page-media, _:future, :root mjx-container {
  will-change: opacity;
}

mjx-math {
  display: inline-block;
  text-align: left;
  line-height: 0;
  text-indent: 0;
  font-style: normal;
  font-weight: normal;
  font-size: 100%;
  font-size-adjust: none;
  letter-spacing: normal;
  border-collapse: collapse;
  word-wrap: normal;
  word-spacing: normal;
  white-space: nowrap;
  direction: ltr;
  padding: 1px 0;
}

mjx-container[jax=&quot;CHTML&quot;][display=&quot;true&quot;] {
  display: block;
  text-align: center;
  margin: 1em 0;
}

mjx-container[jax=&quot;CHTML&quot;][display=&quot;true&quot;][width=&quot;full&quot;] {
  display: flex;
}

mjx-container[jax=&quot;CHTML&quot;][display=&quot;true&quot;] mjx-math {
  padding: 0;
}

mjx-container[jax=&quot;CHTML&quot;][justify=&quot;left&quot;] {
  text-align: left;
}

mjx-container[jax=&quot;CHTML&quot;][justify=&quot;right&quot;] {
  text-align: right;
}

mjx-mi {
  display: inline-block;
  text-align: left;
}

mjx-c {
  display: inline-block;
}

mjx-utext {
  display: inline-block;
  padding: .75em 0 .2em 0;
}

mjx-mo {
  display: inline-block;
  text-align: left;
}

mjx-stretchy-h {
  display: inline-table;
  width: 100%;
}

mjx-stretchy-h &gt; * {
  display: table-cell;
  width: 0;
}

mjx-stretchy-h &gt; * &gt; mjx-c {
  display: inline-block;
  transform: scalex(1.0000001);
}

mjx-stretchy-h &gt; * &gt; mjx-c::before {
  display: inline-block;
  width: initial;
}

mjx-stretchy-h &gt; mjx-ext {
  /* IE */ overflow: hidden;
  /* others */ overflow: clip visible;
  width: 100%;
}

mjx-stretchy-h &gt; mjx-ext &gt; mjx-c::before {
  transform: scalex(500);
}

mjx-stretchy-h &gt; mjx-ext &gt; mjx-c {
  width: 0;
}

mjx-stretchy-h &gt; mjx-beg &gt; mjx-c {
  margin-right: -.1em;
}

mjx-stretchy-h &gt; mjx-end &gt; mjx-c {
  margin-left: -.1em;
}

mjx-stretchy-v {
  display: inline-block;
}

mjx-stretchy-v &gt; * {
  display: block;
}

mjx-stretchy-v &gt; mjx-beg {
  height: 0;
}

mjx-stretchy-v &gt; mjx-end &gt; mjx-c {
  display: block;
}

mjx-stretchy-v &gt; * &gt; mjx-c {
  transform: scaley(1.0000001);
  transform-origin: left center;
  overflow: hidden;
}

mjx-stretchy-v &gt; mjx-ext {
  display: block;
  height: 100%;
  box-sizing: border-box;
  border: 0px solid transparent;
  /* IE */ overflow: hidden;
  /* others */ overflow: visible clip;
}

mjx-stretchy-v &gt; mjx-ext &gt; mjx-c::before {
  width: initial;
  box-sizing: border-box;
}

mjx-stretchy-v &gt; mjx-ext &gt; mjx-c {
  transform: scaleY(500) translateY(.075em);
  overflow: visible;
}

mjx-mark {
  display: inline-block;
  height: 0px;
}

mjx-mn {
  display: inline-block;
  text-align: left;
}

mjx-msup {
  display: inline-block;
  text-align: left;
}

mjx-c::before {
  display: block;
  width: 0;
}

.MJX-TEX {
  font-family: MJXZERO, MJXTEX;
}

.TEX-B {
  font-family: MJXZERO, MJXTEX-B;
}

.TEX-I {
  font-family: MJXZERO, MJXTEX-I;
}

.TEX-MI {
  font-family: MJXZERO, MJXTEX-MI;
}

.TEX-BI {
  font-family: MJXZERO, MJXTEX-BI;
}

.TEX-S1 {
  font-family: MJXZERO, MJXTEX-S1;
}

.TEX-S2 {
  font-family: MJXZERO, MJXTEX-S2;
}

.TEX-S3 {
  font-family: MJXZERO, MJXTEX-S3;
}

.TEX-S4 {
  font-family: MJXZERO, MJXTEX-S4;
}

.TEX-A {
  font-family: MJXZERO, MJXTEX-A;
}

.TEX-C {
  font-family: MJXZERO, MJXTEX-C;
}

.TEX-CB {
  font-family: MJXZERO, MJXTEX-CB;
}

.TEX-FR {
  font-family: MJXZERO, MJXTEX-FR;
}

.TEX-FRB {
  font-family: MJXZERO, MJXTEX-FRB;
}

.TEX-SS {
  font-family: MJXZERO, MJXTEX-SS;
}

.TEX-SSB {
  font-family: MJXZERO, MJXTEX-SSB;
}

.TEX-SSI {
  font-family: MJXZERO, MJXTEX-SSI;
}

.TEX-SC {
  font-family: MJXZERO, MJXTEX-SC;
}

.TEX-T {
  font-family: MJXZERO, MJXTEX-T;
}

.TEX-V {
  font-family: MJXZERO, MJXTEX-V;
}

.TEX-VB {
  font-family: MJXZERO, MJXTEX-VB;
}

mjx-stretchy-v mjx-c, mjx-stretchy-h mjx-c {
  font-family: MJXZERO, MJXTEX-S1, MJXTEX-S4, MJXTEX, MJXTEX-A ! important;
}

@font-face /* 0 */ {
  font-family: MJXZERO;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Zero.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 1 */ {
  font-family: MJXTEX;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Main-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 2 */ {
  font-family: MJXTEX-B;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Main-Bold.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 3 */ {
  font-family: MJXTEX-I;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Math-Italic.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 4 */ {
  font-family: MJXTEX-MI;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Main-Italic.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 5 */ {
  font-family: MJXTEX-BI;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Math-BoldItalic.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 6 */ {
  font-family: MJXTEX-S1;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Size1-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 7 */ {
  font-family: MJXTEX-S2;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Size2-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 8 */ {
  font-family: MJXTEX-S3;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Size3-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 9 */ {
  font-family: MJXTEX-S4;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Size4-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 10 */ {
  font-family: MJXTEX-A;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_AMS-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 11 */ {
  font-family: MJXTEX-C;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 12 */ {
  font-family: MJXTEX-CB;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Bold.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 13 */ {
  font-family: MJXTEX-FR;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Fraktur-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 14 */ {
  font-family: MJXTEX-FRB;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Fraktur-Bold.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 15 */ {
  font-family: MJXTEX-SS;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_SansSerif-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 16 */ {
  font-family: MJXTEX-SSB;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_SansSerif-Bold.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 17 */ {
  font-family: MJXTEX-SSI;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_SansSerif-Italic.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 18 */ {
  font-family: MJXTEX-SC;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Script-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 19 */ {
  font-family: MJXTEX-T;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Typewriter-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 20 */ {
  font-family: MJXTEX-V;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Vector-Regular.woff&quot;) format(&quot;woff&quot;);
}

@font-face /* 21 */ {
  font-family: MJXTEX-VB;
  src: url(&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2/MathJax_Vector-Bold.woff&quot;) format(&quot;woff&quot;);
}

mjx-c.mjx-c1D446.TEX-I::before {
  padding: 0.705em 0.645em 0.022em 0;
  content: &quot;S&quot;;
}

mjx-c.mjx-c5B::before {
  padding: 0.75em 0.278em 0.25em 0;
  content: &quot;[&quot;;
}

mjx-c.mjx-c30::before {
  padding: 0.666em 0.5em 0.022em 0;
  content: &quot;0&quot;;
}

mjx-c.mjx-c5D::before {
  padding: 0.75em 0.278em 0.25em 0;
  content: &quot;]&quot;;
}

mjx-c.mjx-c3C::before {
  padding: 0.54em 0.778em 0.04em 0;
  content: &quot;&lt;&quot;;
}

mjx-c.mjx-c31::before {
  padding: 0.666em 0.5em 0 0;
  content: &quot;1&quot;;
}

mjx-c.mjx-c22EF::before {
  padding: 0.31em 1.172em 0 0;
  content: &quot;\22EF&quot;;
}

mjx-c.mjx-c2212::before {
  padding: 0.583em 0.778em 0.082em 0;
  content: &quot;\2212&quot;;
}

mjx-c.mjx-c1D43B.TEX-I::before {
  padding: 0.683em 0.888em 0 0;
  content: &quot;H&quot;;
}

mjx-c.mjx-c2264::before {
  padding: 0.636em 0.778em 0.138em 0;
  content: &quot;\2264&quot;;
}

mjx-c.mjx-c1D456.TEX-I::before {
  padding: 0.661em 0.345em 0.011em 0;
  content: &quot;i&quot;;
}

mjx-c.mjx-c2208::before {
  padding: 0.54em 0.667em 0.04em 0;
  content: &quot;\2208&quot;;
}

mjx-c.mjx-c2C::before {
  padding: 0.121em 0.278em 0.194em 0;
  content: &quot;,&quot;;
}

mjx-c.mjx-c1D45B.TEX-I::before {
  padding: 0.442em 0.6em 0.011em 0;
  content: &quot;n&quot;;
}

mjx-c.mjx-c29::before {
  padding: 0.75em 0.389em 0.25em 0;
  content: &quot;)&quot;;
}

mjx-c.mjx-c3D::before {
  padding: 0.583em 0.778em 0.082em 0;
  content: &quot;=&quot;;
}

mjx-c.mjx-c7C::before {
  padding: 0.75em 0.278em 0.249em 0;
  content: &quot;|&quot;;
}

mjx-c.mjx-c2265::before {
  padding: 0.636em 0.778em 0.138em 0;
  content: &quot;\2265&quot;;
}

mjx-c.mjx-c3E::before {
  padding: 0.54em 0.778em 0.04em 0;
  content: &quot;&gt;&quot;;
}

mjx-c.mjx-c1D457.TEX-I::before {
  padding: 0.661em 0.412em 0.204em 0;
  content: &quot;j&quot;;
}

mjx-c.mjx-c1D43F.TEX-I::before {
  padding: 0.683em 0.681em 0 0;
  content: &quot;L&quot;;
}

mjx-c.mjx-c2032::before {
  padding: 0.56em 0.275em 0 0;
  content: &quot;\2032&quot;;
}

mjx-c.mjx-c210E.TEX-I::before {
  padding: 0.694em 0.576em 0.011em 0;
  content: &quot;h&quot;;
}

mjx-c.mjx-c1D464.TEX-I::before {
  padding: 0.443em 0.716em 0.011em 0;
  content: &quot;w&quot;;
}

mjx-c.mjx-c1D459.TEX-I::before {
  padding: 0.694em 0.298em 0.011em 0;
  content: &quot;l&quot;;
}

mjx-c.mjx-c1D45F.TEX-I::before {
  padding: 0.442em 0.451em 0.011em 0;
  content: &quot;r&quot;;
}

mjx-c.mjx-c2227::before {
  padding: 0.598em 0.667em 0.022em 0;
  content: &quot;\2227&quot;;
}

mjx-c.mjx-c2200::before {
  padding: 0.694em 0.556em 0.022em 0;
  content: &quot;\2200&quot;;
}

mjx-c.mjx-c1D458.TEX-I::before {
  padding: 0.694em 0.521em 0.011em 0;
  content: &quot;k&quot;;
}

mjx-c.mjx-c2203::before {
  padding: 0.694em 0.556em 0 0;
  content: &quot;\2203&quot;;
}

mjx-c.mjx-c3A::before {
  padding: 0.43em 0.278em 0 0;
  content: &quot;:&quot;;
}

mjx-c.mjx-c2B::before {
  padding: 0.583em 0.778em 0.082em 0;
  content: &quot;+&quot;;
}

mjx-c.mjx-c28::before {
  padding: 0.75em 0.389em 0.25em 0;
  content: &quot;(&quot;;
}

mjx-c.mjx-c1D45C.TEX-I::before {
  padding: 0.441em 0.485em 0.011em 0;
  content: &quot;o&quot;;
}

mjx-c.mjx-c2209::before {
  padding: 0.716em 0.667em 0.215em 0;
  content: &quot;\2209&quot;;
}
&lt;/style&gt;</description><pubDate>Sat, 13 Apr 2024 00:00:00 GMT</pubDate></item><item><title>Preparing for Technical Interviews</title><link>https://blog.woojiahao.com/post/technical-interview-systems</link><guid isPermaLink="true">https://blog.woojiahao.com/post/technical-interview-systems</guid><description>&lt;p&gt;My friend, Devansh, recently wrote an article about
&lt;a href=&quot;https://medium.com/@devanshshah1309/debunking-myths-regarding-tech-internship-applications-c00c69213561&quot;&gt;“Debunking Myths Regarding Tech Internship Applications”&lt;/a&gt;
, and I agree with many of his points. Proofreading his article gave me the opportunity to reflect on my own personal
journey through internship hunting and technical interviews in summer 2024 and I would love to share more about the
systems and techniques I had used to prepare for my technical interviews.&lt;/p&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;I understand that the tech industry is very volatile at the moment and a lot of my “success” this
internship cycle boils down to timing and luck along with a lot of preparations. I am incredibly thankful for the
offers I have received and I will never know what combination of factors led to my ultimate success.&lt;/p&gt;&lt;p&gt;If you are reading this and you have not had as much success so far, please do not stop trying. Keep pushing and you
will definitely get an amazing offer :)&lt;/p&gt;&lt;/div&gt;
&lt;h1 id=&quot;who-am-i&quot;&gt;Who am I?&lt;/h1&gt;
&lt;p&gt;While you are reading this, you may be thinking to yourself, “Who is this person telling me about technical interviews?”
No worries, an introduction is in order. Of course, if you are just interested in the systems and techniques, you can
&lt;a href=&quot;#technical-interviewing-as-a-skill&quot;&gt;jump to them here.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;my-background&quot;&gt;My background&lt;/h2&gt;
&lt;p&gt;I am Jiahao, a Computer Science undergraduate from the National University of Singapore. Before entering
university, I was studying Information Technology in Singapore Polytechnic.&lt;/p&gt;
&lt;p&gt;I was also a complete “noob” at data structures and algorithms and technical interviews (my course in polytechnic never
taught us these subjects). As such, while I had built several projects in my own spare time and worked with various
teams, I was never well-versed in solving these data structure/algorithms problems and would struggle with even simple
LeetCode easy problems (no exaggeration, I would spend an eternity trying to solve
&lt;a href=&quot;https://leetcode.com/problems/two-sum/&quot;&gt;Two Sum&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&quot;first-failures&quot;&gt;First failures…&lt;/h2&gt;
&lt;p&gt;My first true exposure to technical interviews was when I had started applying for internships when I first entered
university. I remember my very first online assessment (OA) was for the &lt;a href=&quot;https://www.grab.com/sg/&quot;&gt;Grab&lt;/a&gt; engineering
internship. Looking back, the questions really were super straightforward, yet I spent the entire one and a half hours
to solve them, and I had still answered them ALL wrongly 😱.&lt;/p&gt;
&lt;p&gt;The rest of the application cycle played out similarly, having failed many of the OAs and even when I had passed to the
subsequent rounds, I would choke and fail at the live codings.&lt;/p&gt;
&lt;p&gt;Thankfully, I still managed to secure a software engineering internship offer at &lt;a href=&quot;https://betafi.co&quot;&gt;Betafi&lt;/a&gt;
where I worked with Elixir + Phoenix to improve the platform (I am very grateful to my supervisor, Ethan, for reaching
out about this opportunity).&lt;/p&gt;
&lt;h2 id=&quot;formal-exposure-to-data-structures-and-algorithms&quot;&gt;Formal exposure to data structures and algorithms&lt;/h2&gt;
&lt;p&gt;The following semester, I took the mandatory &lt;a href=&quot;https://nusmods.com/courses/CS2040S/data-structures-and-algorithms&quot;&gt;data structures and algorithms
course&lt;/a&gt; that all CS undergraduates had to go
through. It was my first real brush with proper data structures and algorithms and it instilled in me the very
fundamentals of algorithmic thinking (thank you Prof Seth!). While I did not score amazingly (I got an A-), it gave me
the basic tools to start exploring algorithms on my own during the summer.&lt;/p&gt;
&lt;h2 id=&quot;turning-point&quot;&gt;Turning point&lt;/h2&gt;
&lt;p&gt;During the summer, I devised a study plan and techniques to help with my preparation for the next internship
cycle, committing myself to becoming good at technical interviews (on top of juggling my internship, summer projects,
and commitments with &lt;a href=&quot;https://www.nushackers.org/&quot;&gt;NUS Hackers&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;As a result of the consistent effort, I was able to subsequently secure 4 offers (out of over 250+ applications),
receiving offers from companies like &lt;a href=&quot;https://www.citadel.com/&quot;&gt;Citadel&lt;/a&gt;, &lt;a href=&quot;https://www.palantir.com/&quot;&gt;Palantir&lt;/a&gt;,
&lt;a href=&quot;https://www.google.com/&quot;&gt;Google&lt;/a&gt;, and &lt;a href=&quot;https://www.paypal.com/sg/home&quot;&gt;PayPal&lt;/a&gt; (all of which I am extremely thankful
for). While the following diagram is not 100% accurate, it hopefully gives you a rough idea on my overall success rate:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/technical-interview-systems/success-sankey.png&quot; alt=&quot;Callback rate&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-am-i-writing-this&quot;&gt;Why am I writing this?&lt;/h2&gt;
&lt;p&gt;While I am not claiming to be an absolute authority of technical interviews, I believe that my experiences, systems, and
techniques had proven to be successful and as such, I would love to share more about them in this article so that you
too can benefit and experience success in your own internship hunt! This article focuses on the “meta-discussion” of
studying for technical interviews and the state of technical interviews in general.&lt;/p&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;If you are interested in my condensed notes for the various topics involved in technical interviews (data structures,
algorithms, system design, behavioral, and resume writing), I have open-sourced my notes as a “Technical Interview
Study Guide” that you can find here: &lt;a href=&quot;https://interviews.woojiahao.com&quot;&gt;https://interviews.woojiahao.com&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;h1 id=&quot;technical-interviewing-as-a-skill&quot;&gt;Technical interviewing as a skill&lt;/h1&gt;
&lt;p&gt;I broadly classify every component of the SWE/SRE interviewing process as a technical interview, so it covers the
OA, initial phone screen, technical onsites, behaviorals, etc.&lt;/p&gt;
&lt;p&gt;To me, technical interviewing is a skill. Much like how you would invest time and energy into getting good at games or
your studies, I believe technical interviewing deserves similar treatment. Similarly, much like gaming or studying,
there are fixed systems and techniques that you can use to streamline this process of improving.&lt;/p&gt;
&lt;p&gt;I will talk about four key aspects of technical interview preparation that I briefly mentioned in my &lt;a href=&quot;https://interviews.woojiahao.com&quot;&gt;Technical
Interview Study Guide&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#creating-a-good-study-plan&quot;&gt;Creating a good study plan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#compiling-useful-notes&quot;&gt;Compiling useful notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#starting-early&quot;&gt;Starting early&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#interviewing-with-a-passion&quot;&gt;Interviewing with a passion&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;creating-a-good-study-plan&quot;&gt;Creating a good study plan&lt;/h2&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Understand your weaknesses, create/use a study plan, and follow a reasonable timeline&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;Prior to creating a study plan, you should first identify your strengths and weaknesses. Before even thinking about the
questions I wanted to finish, I first sat down for about 30 minutes and thought hard about the topics that I found
particularly challenging from my data structure and algorithm course and noted them down. My list looked a little
something like…&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Arrays&lt;/li&gt;
&lt;li&gt;Linked lists&lt;/li&gt;
&lt;li&gt;Dynamic programming&lt;/li&gt;
&lt;li&gt;Greedy algorithms&lt;/li&gt;
&lt;li&gt;Etc…&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As you can see, there is no shame in admitting that you may not be good at what some may even consider as “basic”
topics (after all, you’re doing this preparation for yourself).&lt;/p&gt;
&lt;p&gt;Once you have established what you know and what you don’t know, you can start thinking about a plan of attack (study
plan). A study plan comprises of two key ingredients: a fixed timeline and an exhaustive list of subjects to cover.&lt;/p&gt;
&lt;p&gt;Luckily, &lt;a href=&quot;https://www.linkedin.com/in/yangshun/&quot;&gt;Yangshun&lt;/a&gt; had published a study plan on his &lt;a href=&quot;https://www.techinterviewhandbook.org/&quot;&gt;Tech Interview
Handbook&lt;/a&gt;, where he provides a detailed list of questions per major topic of
technical interviews and a sample timeline to follow. So the first thing I did when I started was to first compile
his list of questions into a Google Sheets document with a slightly adjusted timeline. I used these questions as a
guideline on what to complete. I have since moved this study plan to my &lt;a href=&quot;https://interviews.woojiahao.com/getting-started/study-plan&quot;&gt;Technical Interview Study
Guide&lt;/a&gt;, but this was what planning my study plan
looked like in Google Sheets:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/technical-interview-systems/study-plan.png&quot; alt=&quot;Study plan in Google Sheets&quot;&gt;&lt;/p&gt;
&lt;p&gt;The final secret sauce is to create and follow a reasonable study plan. For me, I used the number of questions and
familiarity with each topic as a gauge for how long I should spend on each topic. For instance, I felt more
comfortable with a topic like recursion so I allocated just a day for eight questions, but for dynamic programming, I
dedicated over five days for it (including the time to internalize and understand each solution).&lt;/p&gt;
&lt;p&gt;You should also include the time it would take to revisit and revise topics. I usually try to revise topics about a week
after having finished their questions to ensure that I’m not forgetting the key concepts.&lt;/p&gt;
&lt;h2 id=&quot;compiling-useful-notes&quot;&gt;Compiling useful notes&lt;/h2&gt;
&lt;p&gt;Once you have a study plan, you can start attempting the questions. Of course, having a systematic way of tackling
problems is quintessential for learning.&lt;/p&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Focus on systematically capturing the intuition of problems and jotting down recurring/unique patterns in problems&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;I use &lt;a href=&quot;https://www.notion.so/&quot;&gt;Notion&lt;/a&gt; to store my notes for every LeetCode question I have attempted since starting
serious preparation. LeetCode has a built-in notetaking functionality and I know others who use tools like Google Sheets
to make such notes. The medium is secondary to the actual process of notetaking and internalizing the intuition of each
problem.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/technical-interview-systems/notion.png&quot; alt=&quot;Notion database for questions&quot;&gt;&lt;/p&gt;
&lt;p&gt;I recommend capturing the following “metadata” about each question:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Concepts used&lt;/li&gt;
&lt;li&gt;Difficulty level (I follow LeetCode’s grading system)&lt;/li&gt;
&lt;li&gt;Should you redo it? (I use this to gauge if I should redo a set of questions)&lt;/li&gt;
&lt;li&gt;Status of completion (for instance, did you give up? Did you solve it the first try?)&lt;/li&gt;
&lt;li&gt;Where the question came from&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These metadata speed up the process of revision and let you revisit questions/topics that you found difficult in the
past.&lt;/p&gt;
&lt;p&gt;After noting these metadata, I use a template for jotting down my notes per question. This template includes the
following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Intuition (base intuition for solving the problem written in your own words)&lt;/li&gt;
&lt;li&gt;Optimizations/notes (any notable optimizations/notes to make of this problem; if I gave up, I would often include the
intuition for my failed attempt here)&lt;/li&gt;
&lt;li&gt;Alternatives (from the LeetCode “Solutions” tab where I try internalizing multiple ways of solving a problem)&lt;/li&gt;
&lt;li&gt;Remarks (any remarks about the problem)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For instance, this is what my note for &lt;a href=&quot;https://leetcode.com/problems/range-sum-of-bst/&quot;&gt;Range Sum in BST&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/technical-interview-systems/sample-note.png&quot; alt=&quot;Note for Range Sum in BST&quot;&gt;&lt;/p&gt;
&lt;p&gt;When approaching a question, try to allocate a fixed time to solve it by before looking at the solution. This varies
per person. This allows you to stay on track with your timeline. However, do not just space out for the alloted time
because you know you will see the answers eventually. Try really hard to come up with the solution and implementing it
within the time. After seeing a solution, start by running through a few examples with the new algorithm, building a
strong intuition for it. Then, start jotting down your notes for the question. Take some time to also read any
alternative solutions as it allows you to learn more about different ways of approaching problems.&lt;/p&gt;
&lt;p&gt;In addition to notes about questions, I also highly recommend notes about the topics. Much like how my &lt;a href=&quot;https://interviews.woojiahao.com&quot;&gt;Technical
Interview Study Guide&lt;/a&gt; includes information about the common patterns in each topic,
I highly recommend making your own notes for these topics (the content of the study guide comes from my own personal
notes!). While you can refer to online sources for these information, having a personalized set of notes is helpful
when it comes to linking concepts and revising! This was what my personal notes looked like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/technical-interview-systems/concepts.png&quot; alt=&quot;Concepts in Notion&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;starting-early&quot;&gt;Starting early&lt;/h2&gt;
&lt;p&gt;All these preparations would be in vain if you only start in the middle of the internship cycle or if you start applying
late.&lt;/p&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Start practicing as early as possible so that you are ready and able to apply to more roles&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;My personal timeline for summer 2024 was as such (taken from my &lt;a href=&quot;https://interviews.woojiahao.com&quot;&gt;Technical Interview Study
Guide&lt;/a&gt;):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Start of May 2023: sourcing for problems and figuring out my weaknesses when it comes to interviewing&lt;/li&gt;
&lt;li&gt;May 2023 to mid June 2023: working on my fundamentals by completing questions by topic&lt;/li&gt;
&lt;li&gt;Mid Jun 2023 to Jul 2023: working on other problems to expand my exposure and speed&lt;/li&gt;
&lt;li&gt;Jul 2023 to Oct 2023: start applying for roles in Singapore, US, and UK&lt;/li&gt;
&lt;li&gt;Aug 2023 to Mar 2024: started interviewing and received my offers&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As you can see, as “kiasu” (Singaporean slang for “fear of losing”) as it is to start the moment summer starts, it is
necessary if you’re attempting to cover as much breadth and achieve as much depth as possible before the internship
applications open. Many large firms in the US opened while it was still the summer in Singapore and many large firms
in Singapore opened soon after the summer ended.&lt;/p&gt;
&lt;h2 id=&quot;interviewing-with-a-passion&quot;&gt;Interviewing with a passion&lt;/h2&gt;
&lt;p&gt;It does not matter how much you prepare for the interview if you cannot convince your interviewers to want you on their
team.&lt;/p&gt;
&lt;div class=&quot;callout info&quot;&gt;&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Research every company in depth and understand their business, projects, and culture and find an alignment with them&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;Every interview with an engineer/manager/HR with the company is a two-way conversation. It is both a way for them to get
to know you as a candidate, but also for you to get to know about the company. However, in order for this conversation
to be effective and meaningful for both parties, you MUST do your due diligence in understanding more about the company.&lt;/p&gt;
&lt;p&gt;A great example is learning about a company’s open-source efforts and understanding these projects and talking to the
engineers about them! I find that finding these “talking points” about the company helped me to not only appear
interested in the company (because I was), but also helped me to ask meaningful questions about the company as my
curiosity would drive me to want to learn more.&lt;/p&gt;
&lt;p&gt;However, this does not just apply to knowing more about the company. Being passionate about your past experiences like
past projects and internships also helps to show that you are someone who is invested. Be proactive in learning about
the industry you were in, the problems you were solving, the technical and non-technical challenges you faced, and how
you contributed to the team. These are all key things that help inform your perspective of these experiences and gives
the interviewer the sense that you CARE about the project beyond just being a “code monkey”.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/post/technical-interview-systems/monkey-developer.gif&quot; alt=&quot;Code monkey&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;I have rambled for long enough.&lt;/p&gt;
&lt;p&gt;If you were to take away just one thing from this, I hope it is this: technical interviews is a skill that takes time
and dedication to improve on. You cannot expect to be amazing at it without any practice, just as you would not expect
to be &lt;a href=&quot;https://www.youtube.com/@magmidt&quot;&gt;Magnus Midtbø&lt;/a&gt; when starting out climbing.&lt;/p&gt;
&lt;p&gt;I hope that this article gives you both hope and guidance on how to navigate your technical interview preparation and I
hope that my &lt;a href=&quot;https://interviews.woojiahao.com&quot;&gt;Technical Interview Study Guide&lt;/a&gt; can become your study buddy throughout
your journey.&lt;/p&gt;
&lt;p&gt;I am wishing you all the best and I am rooting for you! 🤩&lt;/p&gt;
&lt;p&gt;P.S. If you have used my guide or just want to talk to someone about technical interview preparation, feel free to email
me at &lt;a href=&quot;mailto:woojiahao1234@gmail.com&quot;&gt;woojiahao1234@gmail.com&lt;/a&gt;!&lt;/p&gt;</description><pubDate>Sat, 30 Mar 2024 00:00:00 GMT</pubDate></item><item><title>The Story of Elixir</title><link>https://blog.woojiahao.com/post/the-story-of-elixir</link><guid isPermaLink="true">https://blog.woojiahao.com/post/the-story-of-elixir</guid><description>This post was published on https://osshistory.org/p/elixir</description><pubDate>Mon, 15 Jan 2024 00:00:00 GMT</pubDate></item><item><title>A Comprehensive Guide to Using JSON in Go</title><link>https://blog.woojiahao.com/post/a-comprehensive-guide-to-using-json-in-go</link><guid isPermaLink="true">https://blog.woojiahao.com/post/a-comprehensive-guide-to-using-json-in-go</guid><description>This post was published on https://betterstack.com/community/guides/scaling-go/json-in-go/</description><pubDate>Sat, 23 Dec 2023 00:00:00 GMT</pubDate></item><item><title>Redis Caching in Go: A Beginner&apos;s Guide</title><link>https://blog.woojiahao.com/post/redis-caching-in-go</link><guid isPermaLink="true">https://blog.woojiahao.com/post/redis-caching-in-go</guid><description>This post was published on https://betterstack.com/community/guides/scaling-go/redis-caching-golang/</description><pubDate>Sat, 23 Dec 2023 00:00:00 GMT</pubDate></item><item><title>How to Work with SQL Databases in Go</title><link>https://blog.woojiahao.com/post/how-to-work-with-sql-databases-in-go</link><guid isPermaLink="true">https://blog.woojiahao.com/post/how-to-work-with-sql-databases-in-go</guid><description>This post was published on https://betterstack.com/community/guides/scaling-go/sql-databases-in-go/</description><pubDate>Tue, 19 Dec 2023 00:00:00 GMT</pubDate></item><item><title>How to Get Started with Logging in Django</title><link>https://blog.woojiahao.com/post/how-to-get-started-with-logging-in-django</link><guid isPermaLink="true">https://blog.woojiahao.com/post/how-to-get-started-with-logging-in-django</guid><description>This post was published on https://betterstack.com/community/guides/logging/how-to-start-logging-with-django/</description><pubDate>Wed, 06 Dec 2023 00:00:00 GMT</pubDate></item><item><title>Installing UxPlay on Arch Linux</title><link>https://blog.woojiahao.com/post/uxplay-arch-linux</link><guid isPermaLink="true">https://blog.woojiahao.com/post/uxplay-arch-linux</guid><description>&lt;p&gt;I got my iPad Air 4 a few months ago and have been wanting to test the AirPlay functionality on it. However, as I am on
Manjaro Linux - a Linux distribution based on Arch Linux, I was unable to get the native support that MacOS has.&lt;/p&gt;
&lt;p&gt;I stumbled upon &lt;a href=&quot;https://github.com/antimof/UxPlay&quot;&gt;UxPlay&lt;/a&gt; as a potential solution for this problem.&lt;/p&gt;
&lt;p&gt;UxPlay is an AirPlay Unix mirroring server that acts like an AppleTV for screen-mirroring on the machine that is running
the server. It only works on &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix&quot;&gt;UNIX systems.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The README is quite verbose and only contains the package names for Debian, Red Hat, Fedora, CentOS, OpenSUSE, FreeBSD
distros.&lt;/p&gt;
&lt;p&gt;So, this guide aims to help install UxPlay on Arch/Manjaro.&lt;/p&gt;
&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;
&lt;p&gt;Install the necessary dependencies.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;yay&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; cmake&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; pkgconf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;yay&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; openssl&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; libplist&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;yay&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; avahi&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gstreamer&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gst-plugins-base&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gst-libav&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gst-plugins-bad&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;yay&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gstreamer-vaapi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;yay&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; libx11&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# If you are using Manjaro, you can should also install the manjaro-gstreamer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;yay&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; manjaro-gstreamer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Clone the UxPlay repository.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; clone&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; https://github.com/antimof/UxPlay.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; UxPlay&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Build and install the server.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cmake&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;make&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; make&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;UxPlay will be installed to &lt;code&gt;/usr/local/bin/uxplay&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Run the server.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; /usr/local/bin/uxplay&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s all there is to this!&lt;/p&gt;
&lt;h2 id=&quot;optimizing-for-goodnotes-5&quot;&gt;Optimizing for GoodNotes 5&lt;/h2&gt;
&lt;p&gt;One of the main uses I have for AirPlay is to annotate and write notes in GoodNotes 5 without having the worry about the
size constraint. Typically, I would use a 50:50 layout, where one side hosts my annotated notes (like a textbook) and
the other is a notebook for my notes.&lt;/p&gt;
&lt;p&gt;However, with AirPlay, we can configure GoodNotes 5 to mirror only the notes side (displaying it on screen). The other
side will remain the same. This way, the layout can be 25:75 without sacrificing the readability of the notes as the
notes are displayed on a bigger screen while still being controlled via the 25% on the iPad.&lt;/p&gt;</description><pubDate>Tue, 01 Feb 2022 00:00:00 GMT</pubDate></item><item><title>The Javascript Ecosystem Can Be Frustrating to Work With</title><link>https://blog.woojiahao.com/post/javascript-ecosystem-can-be-frustrating-to-work-with</link><guid isPermaLink="true">https://blog.woojiahao.com/post/javascript-ecosystem-can-be-frustrating-to-work-with</guid><description>&lt;p&gt;I have been working with Electron for the past two months or so — building
&lt;a href=&quot;https://github.com/woojiahao/apollo&quot;&gt;Apollo&lt;/a&gt; (open-source RSS aggregator). And working with Electron meant I had to
work with the Javascript ecosystem.&lt;/p&gt;
&lt;p&gt;And boy is the Javascript ecosystem a confusing beast. From trying to bundle Electron via Webpack, to installing React,
to getting hot reloading to work, everything has been a hassle.&lt;/p&gt;
&lt;p&gt;To give even more context, lately, I had finalized the majority of the core functionality of Apollo — which included
things like adding a new feed, and bookmarking feeds. I wanted to polish the application and so I started to modifying
the styles of the React components. However, as I hadn’t setup Electron to allow for hot reloading of the
&lt;a href=&quot;https://www.electronjs.org/docs/latest/tutorial/process-model&quot;&gt;renderer&lt;/a&gt;, it was taking minutes to build and render
the changes. This was not very economical as I could be changing a single text color and have to wait minutes to view
the changes.&lt;/p&gt;
&lt;p&gt;So, I did what any sensible developer would do and look for ways to hot reload an Electron app. I stumbled upon
&lt;code&gt;electron-reloader&lt;/code&gt; and tried it out. No dice. Apparently, it did not work really well with Webpack + React.&lt;/p&gt;
&lt;p&gt;So, I tried the next best thing, using a pre-packed Webpack plugin for &lt;code&gt;electron-reloader&lt;/code&gt;. Again, no dice. The changes
simply were not rendering.&lt;/p&gt;
&lt;p&gt;Exasperated, I decided to re-write my Webpack to use &lt;code&gt;electron-webpack&lt;/code&gt; as it had promised hot reloading out-of-the-box.
But this time, I could not get my existing Webpack configurations to work. &lt;code&gt;electron-webpack&lt;/code&gt; was simply too abstract
for my liking.&lt;/p&gt;
&lt;p&gt;The same happened with &lt;code&gt;electron-forge&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Frustrated with the lack of flexibility and documentation for both &lt;code&gt;electron-webpack&lt;/code&gt; and &lt;code&gt;electron-forge&lt;/code&gt;, I decided to
roll my own “minimal” Electron setup.&lt;/p&gt;
&lt;p&gt;I decided to hardcode the tech stack to be Typescript, React, Tailwind.CSS, and TypeORM. This was the stack that was
already working for me with Apollo and I did not want to rewrite Apollo.&lt;/p&gt;
&lt;p&gt;So, I started reading the documentation and looking at various posts about setting up these tools. I cannot express just
how many times I would follow a guide to the tee and have some random error message appear because the tutorial was like
three months old.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;THREE MONTHS&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Only in Javascript will you get breaking changes by following a three-month old article…&lt;/p&gt;
&lt;p&gt;I was pulling my hair at the multitude of errors with just setting up Webpack to work with every single technology. The
implementation of Apollo was never a trouble, but the setup was the one giving me the most amount of problems…&lt;/p&gt;
&lt;p&gt;Finally, after nearly eight hours of repeated trial and error and constant Google-fu, I finally got the minimal setup
working.&lt;/p&gt;
&lt;p&gt;I think this experience really speaks to the almost tragic state of Javascript. Everything is moving so quickly that
three-month old articles can go obsolete. Tools are so abstracted that it’s almost impossible to make flexible decisions
without needing to pull everything apart. There are so many tools that perform the same operation but differ ever so
slightly that using one over the other would cause red errors to fill your screen. And yet, we are recommending web
development as a “beginner” domain. Sure, having opinionated tooling can make it easy to start out with — but staying
within the confines and diction of each opinion can become stifling and frustrating.&lt;/p&gt;
&lt;p&gt;Sure this whole process has been eye-opening and has taught me a lot about Webpack and Babel. But maybe it’s just me, but
I think that development should be less about confusing setup and debating standards and more about actually developing a
product that matters. I just feel that time can be better invested elsewhere if the ecosystem and tooling is a
lot more cohesive and complete.&lt;/p&gt;
&lt;p&gt;I know my new “minimal” Electron setup is contributing to the problem, but for me, working with the tools at the most
fundamental level — away from the abstracted nonsense — is the easiest way for me to get something working.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://imgs.xkcd.com/comics/standards.png&quot; alt=&quot;Standards&quot;&gt;&lt;/p&gt;
&lt;p&gt;Of course, Electron development is not exactly the traditional starting point for web development and my past experiences
with these libraries have always been less problematic. I think I am just frustrated at the fact that just by adding a
new framework or feature to the mix, all of these tools suddenly stop working properly and the debugging process is
doubly difficult because of the lack of proper documentation.&lt;/p&gt;
&lt;p&gt;So what can we do about this? Well, I believe that this problem stems from a lack of proper documentation. Rather than
adopting the traditional mindset of “This works with a single click”, we should be striving to document how a layer of
abstraction works behind the scenes. What dependencies does it rely on? How do we properly add new dependencies that don’t
strictly play into the tight integration? How do we use this library, add new features, and maintain it as our project
grows? By taking this first step to making libraries easily understandable and modifiable, we minimize the need to double
down on previous standards and can instead, just stick to a single modular library &lt;em&gt;that just works.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In case you are interested, my “minimal” Electron setup can be found &lt;a href=&quot;https://github.com/woojiahao/minimal-electron&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;</description><pubDate>Tue, 21 Dec 2021 00:00:00 GMT</pubDate></item><item><title>Under the Hood of Metaprogramming: Pitfalls of Metaprogramming in Elixir</title><link>https://blog.woojiahao.com/post/pitfalls-of-metaprogramming-in-elixir</link><guid isPermaLink="true">https://blog.woojiahao.com/post/pitfalls-of-metaprogramming-in-elixir</guid><description>This post was published on https://blog.appsignal.com/2021/11/16/pitfalls-of-metaprogramming-in-elixir.html</description><pubDate>Tue, 16 Nov 2021 00:00:00 GMT</pubDate></item><item><title>Under the Hood of Metaprogramming: How to Use Macros</title><link>https://blog.woojiahao.com/post/how-to-use-macros</link><guid isPermaLink="true">https://blog.woojiahao.com/post/how-to-use-macros</guid><description>This post was published on https://blog.appsignal.com/2021/10/26/how-to-use-macros-in-elixir.html</description><pubDate>Tue, 26 Oct 2021 00:00:00 GMT</pubDate></item><item><title>Under the Hood of Metaprogramming: Under the Hood of Macros in Elixir</title><link>https://blog.woojiahao.com/post/under-the-hood-of-macros-in-elixir</link><guid isPermaLink="true">https://blog.woojiahao.com/post/under-the-hood-of-macros-in-elixir</guid><description>This post was published on https://blog.appsignal.com/2021/10/05/under-the-hood-of-macros-in-elixir.html</description><pubDate>Tue, 05 Oct 2021 00:00:00 GMT</pubDate></item><item><title>Under the Hood of Metaprogramming: An Introduction to Metaprogramming in Elixir</title><link>https://blog.woojiahao.com/post/an-introduction-to-metaprogramming-in-elixir</link><guid isPermaLink="true">https://blog.woojiahao.com/post/an-introduction-to-metaprogramming-in-elixir</guid><description>This post was published on https://blog.appsignal.com/2021/09/07/an-introduction-to-metaprogramming-in-elixir.html</description><pubDate>Tue, 07 Sep 2021 00:00:00 GMT</pubDate></item><item><title>Open-source Deep Dive: Broadway (Part 2) - Inner workings of Broadway</title><link>https://blog.woojiahao.com/post/odd-broadway-2</link><guid isPermaLink="true">https://blog.woojiahao.com/post/odd-broadway-2</guid><description>&lt;p&gt;This open-source deep dive has been split into two parts! The first part covers the prerequisite knowledge that would be
good to know when trying to understand the inner workings of Broadway. The second part is an in-depth analysis of the
implementation of various features of Broadway.&lt;/p&gt;
&lt;p&gt;This is the second part of the deep dive and the following topics will be covered:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Batching messages&lt;/li&gt;
&lt;li&gt;Telemetry&lt;/li&gt;
&lt;li&gt;Creating a built-in testing support for pipelines&lt;/li&gt;
&lt;li&gt;Achieving graceful shutdowns&lt;/li&gt;
&lt;li&gt;Other interesting bits of code&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you want a refresher on the concepts behind Broadway (like message queues and concurrency in Elixir) or to better
understand Broadway’s pipeline architecture from a bird’s eye view, you can find the first
part &lt;a href=&quot;open-source-deep-dive-broadway-part-1&quot;&gt;here!&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;whats-the-scoop&quot;&gt;What’s the scoop?&lt;/h1&gt;
&lt;p&gt;Now that we have explored the overall architecture of a Broadway pipeline, we can look at how certain features in
Broadway are implemented.&lt;/p&gt;
&lt;h2 id=&quot;rate-limiting&quot;&gt;Rate limiting&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Rate limiting refers to the act of limiting the amount of data that can be requested or processed in a given period of
time&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Rate limiting is applied across producers within a single pipeline to control the number of events emitted within a
given period of time.&lt;/p&gt;
&lt;p&gt;This is especially useful when the hardware of the machine running the pipeline is not able to keep up with processing
large numbers of events demanded at a time — possibly due to a poorly configured pipeline.&lt;/p&gt;
&lt;p&gt;Some producers do not leverage the rate limiting feature of Broadway. For instance,
the &lt;a href=&quot;https://github.com/dashbitco/broadway/blob/master/lib/broadway/topology/producer_stage.ex&quot;&gt;RabbitMQ producer&lt;/a&gt;
creates an active listener, which means that event emission is not inhibited by the rate limiter. Instead, events are
emitted the moment messages are published to the message queue (
unless &lt;a href=&quot;https://hexdocs.pm/broadway_rabbitmq/BroadwayRabbitMQ.Producer.html#module-back-pressure-and-prefetch_count&quot;&gt;otherwise configured&lt;/a&gt;)
.&lt;/p&gt;
&lt;p&gt;But for the producers that &lt;em&gt;do&lt;/em&gt; leverage the rate limiting — such as
the &lt;a href=&quot;https://github.com/dashbitco/broadway_sqs/blob/master/lib/broadway_sqs/producer.ex&quot;&gt;Amazon SQS producer&lt;/a&gt; — rate
limiting is applied in two instances:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;When consumers make demands to the producer-consumer or producer&lt;/p&gt;
&lt;p&gt;If the producer can still emit events, any demand made by the consumer will be handled by the producer. We take into
account the rate limit threshold. If there are too many events to emit, the excess messages are stored in a message
buffer that will have to be cleared later on.&lt;/p&gt;
&lt;p&gt;Each message that can be emitted will be transformed into the standard event structure that Broadway uses.&lt;/p&gt;
&lt;p&gt;If the producer can no longer emit messages, any demand made is stored in a demand buffer that is cleared later on.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When the rate limit is being reset after the given interval&lt;/p&gt;
&lt;p&gt;After the given interval, the rate limit threshold can be reset. However, we may have accumulated demands and
messages in their respective buffers. We may find that the threshold has not been met before we reset it. Thus, we
can use this remaining threshold to clear any lingering demands and messages stored in their respective buffers.&lt;/p&gt;
&lt;p&gt;Once we have cleared as many messages as our remaining threshold allows, we will reset the threshold and schedule for
another reset. These resets are scheduled at fixed intervals.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The rate limiting threshold is maintained as an &lt;a href=&quot;https://erlang.org/doc/man/atomics.html&quot;&gt;atomic&lt;/a&gt; (discussed later on).
This atomic array is generated by the &lt;code&gt;RateLimiter&lt;/code&gt; process. This module handles all behavior surrounding working with
the rate limit threshold. &lt;code&gt;ProducerStage&lt;/code&gt; handles the actual logic of managing the demands of consumers.&lt;/p&gt;
&lt;p&gt;When the producer cannot emit any more events, i.e. the threshold has been reached, an internal state is set
to &lt;code&gt;:closed&lt;/code&gt; to avoid future demands from being handled.&lt;/p&gt;
&lt;h2 id=&quot;batching&quot;&gt;Batching&lt;/h2&gt;
&lt;p&gt;Batching groups events based on given properties and sends them to designated “sub-pipelines” or batch processors to be
handled. For instance, we might design a pipeline that stores events with even numbers in an S3 bucket and ones with odd
numbers on Google Drive.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Batcher&lt;/code&gt; process is assigned unique names for identification and events that are emitted from the producer must be
tagged to a batcher. Failure to do so will result in a runtime error. This only applies if batching is enabled.&lt;/p&gt;
&lt;p&gt;In order for the producer to send the appropriate events to the respective batcher, a &lt;code&gt;PartitionDispatcher&lt;/code&gt; is used.
Essentially, it defines the behavior of how events are emitted to consumers. A &lt;code&gt;PartitionDispatcher&lt;/code&gt; dispatches events
to certain consumers based on a given criteria (defined as
a &lt;a href=&quot;https://en.wikipedia.org/wiki/Hash_function&quot;&gt;hash function&lt;/a&gt;). In this case, the criterion is the name of the batcher
from the given event. This means that when we assign a batcher to the event, it &lt;strong&gt;will&lt;/strong&gt; be dispatched to only that
batcher. More information about dispatchers in GenStage can be found in
the &lt;a href=&quot;https://hexdocs.pm/gen_stage/GenStage.Dispatcher.html#summary&quot;&gt;official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Even within the batcher, further grouping can be made based on a batch key assigned to the event. This may be used to
ensure that certain events are processed together. Internally, the batcher will accumulate events before emitting them.
However, as it cannot sit around accumulating events forever, a batch is emitted at regular intervals regardless of how
many events are stored in it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;BatchProcessor&lt;/code&gt; process handles a single batch at a time. It is similar to a regular processor, except it works on
a batch of events. The &lt;code&gt;handle_batch&lt;/code&gt; callback is used here.&lt;/p&gt;
&lt;h2 id=&quot;telemetry&quot;&gt;Telemetry&lt;/h2&gt;
&lt;p&gt;Telemetry is used in Broadway to benchmark certain operations that occur such as the duration that a &lt;code&gt;handle_message&lt;/code&gt;
callback takes.&lt;/p&gt;
&lt;p&gt;Broadway relies on the &lt;code&gt;telemetry&lt;/code&gt; &lt;a href=&quot;https://hexdocs.pm/telemetry/&quot;&gt;library&lt;/a&gt;. Within the code, events are emitted when
these operations occur and key measurements such as duration are tracked. Handlers/listeners of these events can be
setup to respond to these events.&lt;/p&gt;
&lt;p&gt;Telemetry is not an Elixir-only feature. It is commonly used to perform application
monitoring. &lt;a href=&quot;https://opentelemetry.io/&quot;&gt;OpenTelemetry&lt;/a&gt; is a really interesting framework that offers powerful
application monitoring through telemetry.&lt;/p&gt;
&lt;h2 id=&quot;built-in-testing&quot;&gt;Built-in testing&lt;/h2&gt;
&lt;p&gt;To test the pipeline, we should focus on ensuring that the data processing aspect of the pipeline works as intended.
However, as we rely on external services for input, it would be hard to coordinate a test suite to work with a live data
source as we may not be able to replicate the data source or publish data to the data source at will due to access
limitations. Thus, Broadway has designed a testing utility that allows us to test the pipeline’s data processing
capacity without relying on the data source.&lt;/p&gt;
&lt;p&gt;Broadway provides a placeholder producer module. This producer does not rely on any data sources. Instead, messages are
emitted directly into the pipeline.&lt;/p&gt;
&lt;p&gt;The producer module should be tested separately if there is core behavior that cannot be tested along with the pipeline.&lt;/p&gt;
&lt;p&gt;This form of unit testing ensures that we reduce potential points of failure in our test suite if any of the
aforementioned problems with using the original data source should surface.&lt;/p&gt;
&lt;h2 id=&quot;graceful-shutdowns&quot;&gt;Graceful shutdowns&lt;/h2&gt;
&lt;p&gt;Broadway boasts about having &lt;a href=&quot;https://hexdocs.pm/broadway/architecture.html#graceful-shutdowns&quot;&gt;graceful shutdowns&lt;/a&gt;.
This is a rather interesting concept to explore as it relies heavily on the concurrency system of Elixir.&lt;/p&gt;
&lt;p&gt;Essentially, the pipeline can only exist in two states — when all components are online and when all components are
shutting down. There is no point in time where a single component will shutdown on its own without being restarted. This
is because of the way that the supervisor of each component declares restart strategies ensuring that should a child
process encounters any errors, it will be restarted without a hitch. This way, the only time where our components can
shut down is when we shut down our main process or pipeline supervisor process. When either process is terminated, we
want to properly handle all remaining events in the pipeline before shutting off every component.&lt;/p&gt;
&lt;p&gt;This is achieved through a mix of concurrency features. But before we can explain how it works, a simple introduction of
exit signals and process termination is due.&lt;/p&gt;
&lt;h3 id=&quot;exit-signals-and-process-termination&quot;&gt;Exit signals and process termination&lt;/h3&gt;
&lt;p&gt;Processes can be &lt;a href=&quot;https://hexdocs.pm/elixir/Process.html#link/1&quot;&gt;linked&lt;/a&gt; to one another. When either process receives an
exit signal — which can occur when the process is terminated forcibly or when it receives an exit signal propagated from
its parent — it will propagate the exit signal to the linked process and that process will terminate as well.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/open-source-deep-dive/broadway/linking.jpg&quot; alt=&quot;Process linking&quot;&gt;&lt;/p&gt;
&lt;p&gt;However, these exit signals can
be &lt;a href=&quot;https://crypt.codemancers.com/posts/2016-01-24-understanding-exit-signals-in-erlang-slash-elixir/&quot;&gt;trapped&lt;/a&gt; instead.
When this occurs, rather than terminating the process that receives the propagated exit signal, the exit signal is sent
as a message, allowing the receiving process to handle the exit as though it was just another message.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; handle_info&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:EXIT&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, from, reason}, state) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	# ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a process is terminated, an
optional &lt;code&gt;terminate/2&lt;/code&gt; &lt;a href=&quot;https://hexdocs.pm/elixir/GenServer.html#c:terminate/2&quot;&gt;callback&lt;/a&gt; can be declared to perform any
cleanup before the process is actually terminated. This is useful if we have any lingering operations that should be
completed before we terminate the process.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/Supervisor.html&quot;&gt;Supervisors&lt;/a&gt; can start a list of child processes and is responsible for
managing the restart strategy of each child. The interaction between a supervisor and &lt;code&gt;terminate&lt;/code&gt; is rather interesting.
When a child is terminated, it is restarted accordingly. When a supervisor terminates, all of its children will also be
terminated. If a child process traps exits, the &lt;code&gt;terminate&lt;/code&gt; callback is called. If not, it will simply terminate
immediately without calling the callback. More information about how supervisor interact with shutdowns can be found in
the official &lt;a href=&quot;https://hexdocs.pm/elixir/Supervisor.html#module-start-and-shutdown&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;back-to-our-regularly-scheduled-deep-dive&quot;&gt;Back to our regularly scheduled deep dive…&lt;/h3&gt;
&lt;p&gt;With a basic understanding of exit trapping and process termination, we can actually understand how graceful shutdowns
in Broadway works.&lt;/p&gt;
&lt;p&gt;When the main process or the pipeline supervisor process is terminated, the main process — which traps exit signals —
will invoke its &lt;code&gt;terminate&lt;/code&gt; callback which will inform the &lt;code&gt;Terminator&lt;/code&gt; process to begin trapping exits and terminate
our pipeline supervisor. As this &lt;code&gt;Terminator&lt;/code&gt; process is a child of the pipeline supervisor, it will invoke its
implementation of &lt;code&gt;terminate&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@impl &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; terminate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(reason, %{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;name:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;supervisor_pid:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; supervisor_pid, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;terminator:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; terminator}) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  Broadway&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Topology&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Terminator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;trap_exit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(terminator)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  ref &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;monitor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(supervisor_pid)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  Process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;exit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(supervisor_pid, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reason_to_signal&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(reason))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  receive&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:DOWN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ^ref, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :persistent_term&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;erase&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(name)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  :ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The exit signal propagates to the other components through their supervisors terminating and they will also invoke
their &lt;code&gt;terminate&lt;/code&gt; callback if they trap exits such as producers disconnecting from the data source.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Terminator&lt;/code&gt; process is responsible for ensuring that all events still within the pipeline are processed before
terminating the pipeline entirely.&lt;/p&gt;
&lt;p&gt;It does so in three phases:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Notify that the processors do not resubscribe to producers through a state flag&lt;/li&gt;
&lt;li&gt;Drain the producers of any events remaining by emitting the events through the pipeline&lt;/li&gt;
&lt;li&gt;Wait for the batch processors (which will be the very last component in the pipeline) to terminate before terminating
the supervisor&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@impl &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; terminate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, state) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; state.first, pid &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;whereis&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(name) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(pid, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:will_terminate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; state.producers, pid &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;whereis&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(name) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    Broadway&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Topology&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ProducerStage&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;drain&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(pid)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; state.last, pid &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;whereis&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(name) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ref &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;monitor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(pid)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    receive&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:done&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ^pid} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:DOWN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ^ref, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  :ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Interestingly, as the producer may be waiting to drain events, we may not want to cancel all of its consumers
immediately. Thus, we rely on &lt;code&gt;GenStage#async_info&lt;/code&gt; to &lt;a href=&quot;https://hexdocs.pm/gen_stage/GenStage.html#async_info/2&quot;&gt;queue&lt;/a&gt;
the message to cancel all consumers at the end of the GenStage message queue — effectively waiting for all other events
to be processed before cancelling all consumers. If batching is enabled, the processors will also wait for the batches
to be processed before cancelling all consumers.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@spec &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;drain&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GenServer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; drain&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(producer) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  GenStage&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;demand&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(producer, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:accumulate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  GenStage&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cast&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(producer, {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:prepare_for_draining&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	# The :cancel_consumers message is added to the end of the message queue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  GenStage&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;async_info&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(producer, {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:cancel_consumers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These mechanisms ensure that all events left in the pipeline is properly processed before the pipeline terminates, thus
achieving graceful shutdowns.&lt;/p&gt;
&lt;h1 id=&quot;fascinating-discovery&quot;&gt;Fascinating discovery!&lt;/h1&gt;
&lt;p&gt;These are some interesting bits of code that Broadway has.&lt;/p&gt;
&lt;h2 id=&quot;__using__-configurations&quot;&gt;&lt;code&gt;__using__&lt;/code&gt; configurations&lt;/h2&gt;
&lt;p&gt;Like other libraries in Elixir, &lt;code&gt;use Broadway&lt;/code&gt; is where it all begins. As discussed in the
previous &lt;a href=&quot;https://woojiahao.github.io/blog/posts/open-source-deep-dive-hound&quot;&gt;open-source deep dive&lt;/a&gt;, the behavior
of &lt;code&gt;use&lt;/code&gt; can be altered by defining the &lt;code&gt;__using__&lt;/code&gt; macro.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmacro&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; __using__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(opts) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  quote&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; location:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :keep&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bind_quoted:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;opts:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; opts, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;module:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; __CALLER__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.module] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @behaviour &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Broadway&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    @doc false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; child_spec&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(arg) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      default &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        id:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(module),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        start:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:start_link&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [arg]},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        shutdown:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :infinity&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      Supervisor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;child_spec&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(default, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Macro&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;escape&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(opts)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    defoverridable&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; child_spec:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are three interesting bits of code in the &lt;code&gt;__using__&lt;/code&gt; macro:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;location: keep&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Used to report runtime errors from inside the quote. Without this, errors are reported where the defined function (
in &lt;code&gt;quote&lt;/code&gt;) is invoked. This is to ensure that we are aware of where the errors are occurring. More information about
this configuration can be
found &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.SpecialForms.html#quote/2-stacktrace-information&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;bind_quoted&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Used to create bindings within the quote. When a binding is created, the value is
automatically &lt;a href=&quot;https://elixir-lang.org/getting-started/meta/quote-and-unquote.html#unquoting&quot;&gt;unquoted&lt;/a&gt; (which
includes evaluation) and the value cannot be unquoted again. This is especially used when we do not want to
re-evaluate the value multiple times.&lt;/p&gt;
&lt;p&gt;More information quoting and unquoting in Elixir can be found in
the &lt;a href=&quot;https://elixir-lang.org/getting-started/meta/quote-and-unquote.html&quot;&gt;official tutorial&lt;/a&gt; and a simplified
explanation and example of binding can be
found &lt;a href=&quot;https://elixirschool.com/en/lessons/advanced/metaprogramming/#binding&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;@behaviour&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Used to define interface-like behavior where modules that adopt these behaviors can implement callbacks defined. In
this case, when a module &lt;code&gt;use Broadway&lt;/code&gt;, it will have to implement certain callbacks like &lt;code&gt;handle_message&lt;/code&gt; while
other callbacks like &lt;code&gt;handle_batch&lt;/code&gt; remain optional.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@callback &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;prepare_messages&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(messages &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()], context &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; term) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@callback &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_message&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(processor &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; atom, message &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Message&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), context &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; term) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            Message&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@callback &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_batch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            batcher &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; atom,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            messages &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            batch_info &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; BatchInfo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            context &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; term&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          ) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@callback &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_failed&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(messages &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()], context &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; term) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Message&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@optional_callbacks &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;prepare_messages:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;handle_batch:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;handle_failed:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More information about typespecs can be found in
the &lt;a href=&quot;https://elixir-lang.org/getting-started/typespecs-and-behaviours.html#adopting-behaviours&quot;&gt;official documentation&lt;/a&gt;
.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;module-metadata-processing&quot;&gt;Module metadata processing&lt;/h2&gt;
&lt;p&gt;While on the topic of meta-programming, module metadata can also be processed.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ensure_loaded?&lt;/code&gt; ensures that a given module is loaded. In Broadway, this is used to ensure that the &lt;code&gt;:persistent_term&lt;/code&gt;
module from Erlang is available for Elixir — the only time it will not be available is when the version of Elixir is too
old. Documentation &lt;a href=&quot;https://hexdocs.pm/elixir/Code.html#ensure_loaded?/1&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;unless&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Code&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ensure_loaded?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:persistent_term&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  require&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Logger&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  Logger&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Broadway requires Erlang/OTP 21.3+&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  raise&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Broadway requires Erlang/OTP 21.3+&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;function_exported?&lt;/code&gt; returns whether a module contains a definition for a &lt;strong&gt;public&lt;/strong&gt; function with a given arity. Used
to execute functions from modules if they are defined.
Documentation &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.html#function_exported?/3&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Code&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ensure_loaded?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(producer_mod) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;and&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;     function_exported?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(producer_mod, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:prepare_for_start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  case&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; producer_mod.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;prepare_for_start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(module, opts) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {child_specs, opts} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; is_list&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(child_specs) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      {child_specs, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;NimbleOptions&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;validate!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(opts, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Broadway&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Options&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;definition&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;())}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    other &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;			# ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;dynamic-process-naming&quot;&gt;Dynamic process naming&lt;/h2&gt;
&lt;p&gt;As the pipeline can comprise of any number of components, Broadway supports dynamically generated processes. These
dynamically generated processes are assigned names that follow a fixed convention — comprising of the name of the
pipeline, the process type, and the index of the component among the other components of the same type.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defp&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; process_name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(prefix, type, index) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  :&quot;#{&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;name_prefix&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;(prefix)}.#{type}_#{index}&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defp&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; process_names&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(prefix, type, config) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; index &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(config[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:concurrency&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    process_name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(prefix, type, index)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The names are returned as quoted atoms where the atom has a space in it so it has to be declared via &lt;code&gt;:&quot;&quot;&lt;/code&gt; .&lt;/p&gt;
&lt;h2 id=&quot;storage-options-in-elixir&quot;&gt;Storage options in Elixir&lt;/h2&gt;
&lt;p&gt;Besides the basic data structures like lists and dictionaries, Elixir and Erlang offer other ways of storing data within
processes.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://erlang.org/doc/man/atomics.html&quot;&gt;Atomics&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:atomics&lt;/code&gt; are a way of performing atomic operations on a set of mutable atomic variables.&lt;/p&gt;
&lt;p&gt;Used to maintain the rate limiting threshold.&lt;/p&gt;
&lt;p&gt;Previously, the rate limiter used &lt;a href=&quot;https://erlang.org/doc/man/ets.html&quot;&gt;ETS&lt;/a&gt; instead but atomic operations are much
better for concurrent systems as they avoid race conditions when multiple producer processes are attempting to modify
the rate limit.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;counter &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :atomics&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(@atomics_index, [])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:atomics&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(counter, @atomics_index, allowed)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://erlang.org/doc/man/persistent_term.html&quot;&gt;Persistent term&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Storage for Erlang terms that is optimised for reading terms at the expense of writing and updating terms.&lt;/p&gt;
&lt;p&gt;Used to store pipeline metadata like producer names etc.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:persistent_term&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(config.name, %{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  context:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; config.context,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  producer_names:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; process_names&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(config.name, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Producer&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, config.producer_config),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  batchers_names:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    Enum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(config.batchers_config, &amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(config.name, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Batcher&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;elem&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&amp;#x26;1, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  rate_limiter_name:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    config.producer_config[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:rate_limiting&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RateLimiter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;rate_limiter_name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(opts[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://erlang.org/doc/man/queue.html&quot;&gt;Queue&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Manage first-in, first-out queues.&lt;/p&gt;
&lt;p&gt;Used to manage message and demand buffers in the producer.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# A queue of &quot;batches&quot; of messages that we buffered.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;message_buffer:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :queue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# A queue of demands (integers) that we buffered.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;demand_buffer:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :queue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/Process.html&quot;&gt;Process dictionaries&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Store state within a process directly although its usage is
generally &lt;a href=&quot;https://elixirforum.com/t/is-it-a-good-idea-to-store-context-in-process-dictionary-registry-for-http-requests/3142&quot;&gt;frowned upon&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Used to store batches in the batcher.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defp&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; init_or_get_batch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(batch_key, state) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; batch &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(batch_key) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    batch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;		# ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defp&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; put_batch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(batch_key, {&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; batch) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  Process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(batch_key, batch)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A better alternative might have been to use an &lt;a href=&quot;https://hexdocs.pm/elixir/Agent.html&quot;&gt;Agent&lt;/a&gt; or ETS instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit!&lt;/strong&gt; I clarified with the team about their decision to use process dictionaries over ETS, this was their
response:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The correct solution here would be to simply use a map. But because this is very intensive code, we need a mutable
option, and the process dictionary is the most efficient one. ETS would be slow as data has to be copied in and out
of ETS.
This is one of the very cases where using the pdict for performance is justified. :)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, the reason why they decided to use a process dictionary over ETS is due to the performance requirement of
batching! Very interesting!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;options-validation&quot;&gt;Options validation&lt;/h2&gt;
&lt;p&gt;Dashbit — the team behind Broadway — developed an options validation library
called &lt;a href=&quot;https://github.com/dashbitco/nimble_options&quot;&gt;NimbleOptions&lt;/a&gt; that aims to be a small library for validating and
documenting high-level options.&lt;/p&gt;
&lt;p&gt;A set of definitions for the available options are created first and these can be used to validate a keyword list — aka
the options.&lt;/p&gt;
&lt;p&gt;If the options are invalid, an error is returned, otherwise an &lt;code&gt;:ok&lt;/code&gt; status along with the options are returned. The
returned options have default values filled in.&lt;/p&gt;
&lt;h2 id=&quot;default-values-in-dictionaries&quot;&gt;Default values in dictionaries&lt;/h2&gt;
&lt;p&gt;Broadway has an interesting way of fanning out default values for the options keyword list. In the options keyword list,
a “parent” value for &lt;code&gt;:partition_by&lt;/code&gt;, &lt;code&gt;:hibernate_after&lt;/code&gt;, and &lt;code&gt;:spawn_opt&lt;/code&gt; is provided.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;options &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;	partition_by:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;., &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# these are parent values&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;	hibernate_after:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;	producer:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;		hibernate_after:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# this is a child value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The parent value will be used for producers, processors, and batchers if no explicit child value is provided.
Alternatively, we might want to fan out a parent value to only two of the three unset child values while maintaining the
original child value of the third.&lt;/p&gt;
&lt;p&gt;This is done by &lt;a href=&quot;https://hexdocs.pm/elixir/Keyword.html#merge/2&quot;&gt;merging&lt;/a&gt; the child options into the parent options.
Thus, if the child does not define a value for the option, the parent value is inherited.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;opts &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  opts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  |&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; carry_over_one&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:producer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:hibernate_after&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:spawn_opt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  |&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; carry_over_many&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:processors&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:partition_by&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:hibernate_after&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:spawn_opt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  |&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; carry_over_many&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:batchers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:partition_by&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:hibernate_after&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:spawn_opt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defp&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; carry_over_one&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(opts, key, keys) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  update_in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(opts[key], &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Keyword&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;merge&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Keyword&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(opts, keys), value) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defp&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; carry_over_many&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(opts, key, keys) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  update_in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(opts[key], &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    defaults &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Keyword&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(opts, keys)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {k, v} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {k, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Keyword&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;merge&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(defaults, v)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;closing-the-curtains&quot;&gt;Closing the curtains&lt;/h1&gt;
&lt;p&gt;To conclude, Broadway is a powerful library for building data processing pipelines. These pipelines are built on top of
the robust concurrency system that Elixir boasts.&lt;/p&gt;
&lt;p&gt;Broadway is a very versatile library and the documentation contains detailed guides about using it with various data
sources. Check out the &lt;a href=&quot;https://github.com/dashbitco/broadway&quot;&gt;Github repository&lt;/a&gt;
and &lt;a href=&quot;https://hexdocs.pm/broadway/Broadway.html#content&quot;&gt;documentation!&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you want to get a basic understanding of the underlying concepts of Broadway or better visualise the architecture of
a pipeline in Broadway, check out the first part &lt;a href=&quot;/post/odd-broadway-1&quot;&gt;here!&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Open-source Deep Dive is a series where I pick apart open-source projects to explain the underlying concepts that power
these projects and share my findings about the project!&lt;/p&gt;</description><pubDate>Tue, 13 Apr 2021 00:00:00 GMT</pubDate></item><item><title>Open-source Deep Dive: Broadway (Part 1) - Message queues, concurrency in Elixir, and Broadway architecture</title><link>https://blog.woojiahao.com/post/odd-broadway-1</link><guid isPermaLink="true">https://blog.woojiahao.com/post/odd-broadway-1</guid><description>&lt;p&gt;This open-source deep dive has been split into two parts! The first part covers the prerequisite knowledge that would be
good to know when trying to understand the inner workings of Broadway. The second part is an in-depth analysis of the
implementation of various features of Broadway.&lt;/p&gt;
&lt;p&gt;This is the first part of the deep dive and the following topics will be covered:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A brief introduction to what Broadway is&lt;/li&gt;
&lt;li&gt;Message queues&lt;/li&gt;
&lt;li&gt;Concurrency in Elixir&lt;/li&gt;
&lt;li&gt;Producer/consumer model &amp;#x26; GenStage&lt;/li&gt;
&lt;li&gt;Architecture of a Broadway pipeline&lt;/li&gt;
&lt;li&gt;Construction of producer &amp;#x26; processor components&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you wish to jump right into the meat of Broadway, you can find the second
part &lt;a href=&quot;open-source-deep-dive-broadway-part-2&quot;&gt;here!&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;act-1-scene-1&quot;&gt;&lt;strong&gt;Act 1, Scene 1&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;You have just received your latest feature to work on and it is to build a system that receives transaction information
from a message queue, maps the customer code in this transaction information to the customer’s information, and stores
this collective information in a separate database to be queried for customer transaction analysis. Your boss has
developed an obsession with Elixir recently and is now pushing for every project to use it. Gasp.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You start researching for libraries that can do exactly that and stumble
upon &lt;a href=&quot;https://github.com/dashbitco/broadway&quot;&gt;Broadway&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;…build &lt;strong&gt;[concurrent]&lt;/strong&gt; and &lt;strong&gt;[multi-stage]&lt;/strong&gt; &lt;strong&gt;[data ingestion]&lt;/strong&gt; and &lt;strong&gt;[data processing] [pipelines]&lt;/strong&gt;…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Oh boy… that — that is a mouthful… Let’s break it down, shall we?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;concurrent&lt;/strong&gt; - having two or more computations in progress at the same time; &lt;em&gt;in progress&lt;/em&gt; meaning that they do not
have to be executed at the same time (
definition &lt;a href=&quot;https://www.oreilly.com/library/view/the-art-of/9780596802424/&quot;&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;multi-stage&lt;/strong&gt; - successive operating stages (
definition &lt;a href=&quot;https://www.merriam-webster.com/dictionary/multistage&quot;&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;data ingestion&lt;/strong&gt; - process of moving data from one source to a destination for further storage and analysis (
definition &lt;a href=&quot;https://www.alooma.com/blog/what-is-data-ingestion#:~:text=Data%20ingestion%20is%20a%20process,%2C%20CSVs%2C%20or%20from%20streams.&quot;&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;data processing&lt;/strong&gt; - conversion of data into a usable and desirable form (
definition &lt;a href=&quot;https://planningtank.com/computer-applications/data-processing#:~:text=Data%20processing%20is%20the%20conversion,devices%2C%20and%20thus%20done%20automatically.&quot;&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pipelines&lt;/strong&gt; - series of data processing elements (
definition &lt;a href=&quot;https://en.wikipedia.org/wiki/Pipeline_(computing)#:~:text=In%20computing%2C%20a%20pipeline%2C%20also,or%20in%20time%2Dsliced%20fashion.&quot;&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In essence, Broadway builds systems that behave like factory assembly lines. Raw materials (data) is fed into the
assembly line (Broadway pipeline) which is then pieced together to create the end product or other components used in
the final product. The factory has multiple identical assembly lines running so raw material can be fed into any of
these lines to be worked on.&lt;/p&gt;
&lt;p&gt;For your use case, the flow of data will look something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/open-source-deep-dive/broadway/pipeline.jpg&quot; alt=&quot;Sample scenario flowchart&quot;&gt;&lt;/p&gt;
&lt;p&gt;So how does Broadway achieve all of this?&lt;/p&gt;
&lt;h1 id=&quot;lights-camera-action&quot;&gt;Lights! Camera! Action!&lt;/h1&gt;
&lt;p&gt;Before understanding the internals of Broadway, we should establish some basic knowledge of the technologies we will be
using so that we won’t be headless chickens running into this.&lt;/p&gt;
&lt;p&gt;Broadway revolve around the following concepts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;message queues&lt;/li&gt;
&lt;li&gt;concurrency in Elixir&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;what-are-message-queues&quot;&gt;What are message queues?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Note!&lt;/strong&gt; While Broadway can integrate with many types of data sources, the core examples given in the project focus on
message queues as the primary data source.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Message queues are like containers that hold sequences of work objects — called messages — that are to be consumed and
processed. It aids with building asynchronous modular and concurrent systems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Messages are created and delivered to these queues by &lt;strong&gt;producers&lt;/strong&gt; and taken from these queues for processing by **
consumers.** These messages can vary from something as simple as plain information to more complex structures like
requests or — in our case — transaction information.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/open-source-deep-dive/broadway/message_queue.png&quot; alt=&quot;Message queue architecture&quot;&gt;&lt;/p&gt;
&lt;p&gt;Message queues are useful for &lt;strong&gt;decentralising the communication mechanism of large systems&lt;/strong&gt; by acting as a medium for
exchanging events between systems which allows for systems to be easily scaled and distributed.&lt;/p&gt;
&lt;p&gt;This is a reduced explanation of what a message queue is and what it is capable of. For more information about message
queues, the &lt;a href=&quot;https://aws.amazon.com/message-queue/&quot;&gt;Amazon documentation&lt;/a&gt; and
this &lt;a href=&quot;https://www.cloudamqp.com/blog/what-is-message-queuing.html#:~:text=A%20message%20queue%20is%20a,some%20headers%20at%20the%20top.&quot;&gt;blog post&lt;/a&gt;
by CloudAMQP are good places to start.&lt;/p&gt;
&lt;h2 id=&quot;concurrency-in-elixir&quot;&gt;Concurrency in Elixir&lt;/h2&gt;
&lt;p&gt;Broadway relies heavily on concurrency in Elixir. The topology (architecture) of a pipeline is built on top of processes
and many of the features are achieved using the robust concurrency model of Elixir. So what exactly is the concurrency
model in Elixir?&lt;/p&gt;
&lt;p&gt;Elixir employs the &lt;strong&gt;actor concurrency model&lt;/strong&gt;. In this model, actors are defined as &lt;strong&gt;self-isolated units of
processing&lt;/strong&gt;. In Elixir, these actors are called &lt;strong&gt;processes&lt;/strong&gt; and they are managed by
the &lt;a href=&quot;https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine)#:~:text=BEAM%20is%20the%20virtual%20machine,beam%20file%20extension.&quot;&gt;Erlang VM&lt;/a&gt;
. Elixir code is run in each process and a default/main process is akin to that of
the &lt;a href=&quot;https://cocoacasts.com/swift-and-cocoa-fundamentals-what-is-the-main-thread&quot;&gt;main thread&lt;/a&gt; in other concurrency
models.&lt;/p&gt;
&lt;p&gt;Each process communicates via &lt;strong&gt;asynchronous message passing&lt;/strong&gt;. Think of a process as a mailbox of sorts; it has a “bin”
to receive incoming messages and it possess an “address” for other processes to identify it by.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/open-source-deep-dive/broadway/actor_concurrency_model.png&quot; alt=&quot;Actor concurrency model visualisation&quot;&gt;&lt;/p&gt;
&lt;p&gt;The unique aspect of this model is the &lt;strong&gt;lack of shared mutable state&lt;/strong&gt; that other concurrency models rely on. Rather,
state is exclusive to each process.&lt;/p&gt;
&lt;p&gt;In order for the state of a process to be altered, the owner process must make the alteration either on request or
internally due to certain changes.&lt;/p&gt;
&lt;p&gt;The topic of concurrency in Elixir is vast and Elixir provides many other features surrounding its concurrency model
such as &lt;a href=&quot;https://elixir-lang.org/getting-started/mix-otp/genserver.html&quot;&gt;GenServer&lt;/a&gt;. This section is a short preview of
what the actor concurrency model and concurrency in Elixir is all about. For more information, you can refer to
this &lt;a href=&quot;https://berb.github.io/diploma-thesis/original/054_actors.html&quot;&gt;thesis paper&lt;/a&gt; and
the &lt;a href=&quot;https://en.wikipedia.org/wiki/Actor_model#:~:text=The%20actor%20model%20in%20computer,universal%20primitive%20of%20concurrent%20computation.&amp;#x26;text=Actors%20may%20modify%20their%20own,for%20lock%2Dbased%20synchronization&quot;&gt;Wikipedia article&lt;/a&gt;
talking about the actor concurrency model and the
official &lt;a href=&quot;https://elixir-lang.org/getting-started/processes.html&quot;&gt;documentation&lt;/a&gt; and
this &lt;a href=&quot;https://serokell.io/blog/elixir-otp-guide&quot;&gt;tutorial&lt;/a&gt; on OTP in Elixir for more examples of concurrency in Elixir.&lt;/p&gt;
&lt;h2 id=&quot;cue-the-producerconsumer-model&quot;&gt;Cue the producer/consumer model&lt;/h2&gt;
&lt;p&gt;Using the actor concurrency model as a foundation, another concurrency pattern can be modelled in Elixir — the
producer/consumer model.&lt;/p&gt;
&lt;p&gt;This model aims to allow for decoupled data production and consumption by setting up two separate processes to handle
each task — effectively creating a logical separation of concerns.&lt;/p&gt;
&lt;p&gt;However, the producer/consumer model faces a critical issue — what happens if the producer generates excessive messages
for the consumer? The consumer will be overwhelmed and will eventually fail trying to keep up with processing that many
messages. This is
where &lt;a href=&quot;https://medium.com/@jayphelps/backpressure-explained-the-flow-of-data-through-software-2350b3e77ce7&quot;&gt;back pressure&lt;/a&gt;
comes into play.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Back pressure is a control mechanism for how much a producer should emit based on consumer demand, consumer message
buffering, or limited sampling&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Back pressure avoids the problem of overloading the consumer with messages by applying one of or a combination of the
three methods mentioned above (more information in the
link &lt;a href=&quot;https://medium.com/@jayphelps/backpressure-explained-the-flow-of-data-through-software-2350b3e77ce7&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&quot;the-next-frontier-of-concurrency-genstage&quot;&gt;The next frontier (of concurrency): GenStage&lt;/h2&gt;
&lt;p&gt;Seeing the value of having a standard implementation for the producer/consumer model, the Elixir team decided to develop
exactly that.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;GenStage is a specification for exchanging events between producers and consumers with back pressure between Elixir
processes&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Producers &lt;strong&gt;emit events&lt;/strong&gt; to consumers for &lt;strong&gt;processing&lt;/strong&gt;. The events can be of any structure.&lt;/p&gt;
&lt;p&gt;The control mechanism used is a demand system. Consumers inform producers of how many events they can handle (demand)
and producers emits no more than the demanded amount. This ensures that the consumers are capable of handling the events
emitted.&lt;/p&gt;
&lt;p&gt;Producer-consumers behave like both producers and consumers. They are used to perform transformations on events emitted
by the producer before they are emitted to the consumer.&lt;/p&gt;
&lt;p&gt;Similar to &lt;a href=&quot;https://hexdocs.pm/elixir/GenServer.html&quot;&gt;GenServer&lt;/a&gt;, stages in GenStage exchange events
through &lt;a href=&quot;https://hexdocs.pm/gen_stage/GenStage.html#module-callbacks&quot;&gt;callbacks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When a demand is handled — i.e. producer emits events and demanding consumer handles these events — another demand is
made, creating a cycle where both stages are always working - ideally.&lt;/p&gt;
&lt;p&gt;GenStage is a powerful tool in an Elixir developer’s arsenal. More information can be found in
the &lt;a href=&quot;https://elixir-lang.org/blog/2016/07/14/announcing-genstage/&quot;&gt;official announcement&lt;/a&gt; where a little bit of history
of how GenStage came to be was discussed and in a talk by &lt;a href=&quot;https://youtu.be/XPlXNUXmcgE&quot;&gt;José Valim&lt;/a&gt; — creator of
Elixir.&lt;/p&gt;
&lt;p&gt;With a better grasp of the overarching concepts used in Broadway, we can finally discuss what Broadway is all about and
how it does what it does!&lt;/p&gt;
&lt;h1 id=&quot;pipeline-architecture&quot;&gt;Pipeline architecture&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/open-source-deep-dive/broadway/architecture.jpg&quot; alt=&quot;Pipeline architecture&quot;&gt;&lt;/p&gt;
&lt;p&gt;It is at this juncture where it would be important to clarify the term “producer”. In both message queues and GenStage,
a producer is a creator of messages or events. However, in Broadway, a producer is both a consumer of messages and an
emitter of events.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/open-source-deep-dive/broadway/terminology.jpg&quot; alt=&quot;Terminology clarification for Broadway producer&quot;&gt;&lt;/p&gt;
&lt;p&gt;For the rest of the article, the following definitions for the following terminology will be used:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;producer&lt;/strong&gt; — producer of events in Broadway&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;message&lt;/strong&gt; — message in a message queue or any other data source&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;event&lt;/strong&gt; — GenStage events&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When messages are consumed by the producer, they will be transformed into events with a fixed structure defined by
Broadway.&lt;/p&gt;
&lt;p&gt;Each component is a separate process and they are dynamically generated as different topologies (architectures) can be
designed. The order of initialisation for a typical pipeline looks something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/open-source-deep-dive/broadway/order_of_initialisation.jpg&quot; alt=&quot;Order of initialisation&quot;&gt;&lt;/p&gt;
&lt;p&gt;The producers and processors are both created using interesting conventions that is will be explored now. Other
components will be discussed later on as they tie into other features Broadway has.&lt;/p&gt;
&lt;h2 id=&quot;how-its-made-producers&quot;&gt;How it’s made: Producers&lt;/h2&gt;
&lt;p&gt;Producers are built using a pattern similar to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Strategy_pattern&quot;&gt;strategy pattern&lt;/a&gt;
but modified to integrate with the concurrency system in Elixir.&lt;/p&gt;
&lt;p&gt;Different data sources require different methods of establishing connections and receiving messages. Thus, we break up
the producer process into two modules — &lt;code&gt;ProducerStage&lt;/code&gt; defines the behavior for enforcing the rate limit while a
dynamically loaded module defines the behavior for establishing a connection to the data source and receiving messages.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ProducerStage&lt;/code&gt; assumes that the dynamically loaded module contains the typical GenStage callbacks like &lt;code&gt;handle_call&lt;/code&gt;
and &lt;code&gt;handle_demand&lt;/code&gt; and uses them for things like rate limiting.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ProducerStage&lt;/code&gt; behaves as the context while the dynamic module behaves as the strategy. The dynamic module adopts
the &lt;code&gt;Producer&lt;/code&gt; module — which defines two callbacks for managing the overall producer life-cycle.&lt;/p&gt;
&lt;p&gt;To load the module dynamically, the module name is passed to &lt;code&gt;ProducerStage&lt;/code&gt; as an argument. To keep the producer as a
single process, we call the &lt;code&gt;init&lt;/code&gt; function of the module directly when initialising the &lt;code&gt;ProducerStage&lt;/code&gt;. This way, the
module will initialise under the newly spawned process for &lt;code&gt;ProducerStage&lt;/code&gt; rather than spawning an entirely new process.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@impl &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({args, index}) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {module, arg} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; args[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	# ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  state &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    module:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; module,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    module_state:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    transformer:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; transformer,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    consumers:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    rate_limiting:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; rate_limiting_state&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	# Calling the init function of the dynamically loaded module&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  case&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; module.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(arg) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;		# ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When &lt;code&gt;start_link&lt;/code&gt; is called, a new process is spawned first before the &lt;code&gt;init&lt;/code&gt; function is called under the new process.&lt;/p&gt;
&lt;p&gt;This is done as certain message queue providers like &lt;a href=&quot;https://github.com/dashbitco/broadway_rabbitmq&quot;&gt;RabbitMQ&lt;/a&gt; attach
active listeners to the calling process so spawning a separate process for this would mean having to manage two separate
processes for a producer.&lt;/p&gt;
&lt;h2 id=&quot;how-its-made-processors&quot;&gt;How it’s made: Processors&lt;/h2&gt;
&lt;p&gt;Processors are created using a concept similar
to &lt;a href=&quot;https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)&quot;&gt;inheritance&lt;/a&gt; in object-oriented
programming. This idea comes from the need to standardise the subscription logic of producer-consumers and consumers.&lt;/p&gt;
&lt;p&gt;When a processor is started using &lt;code&gt;start_link&lt;/code&gt;, a process of the &lt;code&gt;Subscriber&lt;/code&gt; module is started with the current
processor module passed as a argument.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; start_link&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(args, stage_options) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  Broadway&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Topology&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Subscriber&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_link&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    __MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    args[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:producers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    args,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    Keyword&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(args[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:processor_config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:min_demand&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:max_demand&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    stage_options&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The current module is initialised in the &lt;code&gt;Subscriber&lt;/code&gt; process through &lt;code&gt;init&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@impl &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({module, names, options, subscription_options}) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {type, state, init_options} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; module.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(options)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	# ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Other producer-consumers and consumers like batcher and batch processors also use this pattern to create their
respective GenStage stages.&lt;/p&gt;
&lt;p&gt;A separation of concern is achieved using this pattern. The processor is responsible for event handling while the
subscriber handles the subscription logic.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;That’s a basic rundown of the concepts underpinning Broadway. While it may not be a complete and intensive explanation
of everything, hopefully it is able to provide some clarity. In the next part, we will be exploring how features in
Broadway have been implemented!&lt;/p&gt;
&lt;p&gt;Hop on over to the second part &lt;a href=&quot;/post/odd-broadway-2&quot;&gt;here!&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Open-source Deep Dive is a series where I pick apart open-source projects to explain the underlying concepts that power
these projects and share my findings about the project!&lt;/p&gt;</description><pubDate>Mon, 12 Apr 2021 00:00:00 GMT</pubDate></item><item><title>Open-source Deep Dive: Hound</title><link>https://blog.woojiahao.com/post/odd-hound</link><guid isPermaLink="true">https://blog.woojiahao.com/post/odd-hound</guid><description>&lt;div class=&quot;callout danger&quot;&gt;&lt;p&gt;I do not condone the use of browser automation or torrenting for illegal purposes. Any links or discussions
about the mentioned subjects are purely for educational purposes and should remain as that.&lt;/p&gt;&lt;/div&gt;
&lt;h2 id=&quot;what-is-hound&quot;&gt;What is Hound?&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;For browser automation and writing integration tests in Elixir&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let’s inspect this definition a little closer…&lt;/p&gt;
&lt;h3 id=&quot;what-is-browser-automation&quot;&gt;What is browser automation?&lt;/h3&gt;
&lt;p&gt;Browser automation is effectively the process of using a &lt;strong&gt;proxy&lt;/strong&gt; (like Selenium or Hound) to perform browser actions
on behalf of the user (like the test case). Essentially, we are &lt;strong&gt;automating the usage of the browser.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It is often associated with illegal applications like sneaker-botting but much
like &lt;a href=&quot;https://www.makeuseof.com/tag/8-legal-uses-for-bittorrent-youd-be-surprised/&quot;&gt;torrenting&lt;/a&gt;, there are positive
applications and we will be exploring one of them in this post - integration testing.&lt;/p&gt;
&lt;h3 id=&quot;what-is-integration-testing&quot;&gt;What is integration testing?&lt;/h3&gt;
&lt;p&gt;When building software, we first build individual components to support given functional requirements. These individual
components can be tested using unit tests - which ensure that given a set of inputs, the component returns a &lt;strong&gt;predictable&lt;/strong&gt; set of outputs (predictable means that the functions tested are pure).&lt;/p&gt;
&lt;p&gt;However, while components may work well on their own, when combined with other components (to form larger
components/whole systems), unexpected behavior may be exhibited. For instance, the input from component A is transformed
before it is used as input to component B, thus, the combined components returns an unexpected result.&lt;/p&gt;
&lt;p&gt;Hence, integration tests serve to &lt;strong&gt;bridge the gap between individual components testing and full system testing.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When combined with browser automation, we can ensure that a website works end-to-end. We can ensure that the data
validation on the front-end works as intended and that the forms submitted by users are properly sent to the back-end
and saved in the database.&lt;/p&gt;
&lt;h3 id=&quot;approaching-browser-automation-integration-testing&quot;&gt;Approaching browser automation integration testing…&lt;/h3&gt;
&lt;p&gt;We can take two approaches to browser automation integration testing. We could either&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;build our own interfacing system to communicate with the browser, or&lt;/li&gt;
&lt;li&gt;rely on existing interfacing systems&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The former is time-consuming and requires a lot of care during development as we have to account for varying browser
APIs and quirks. Thus, it is wiser to chose the latter when approaching browser automation integration testing. Doing so
minimizes the number of components we have to manage.&lt;/p&gt;
&lt;h3 id=&quot;introducing-hound&quot;&gt;Introducing Hound!&lt;/h3&gt;
&lt;p&gt;This is where Hound comes into the picture. Hound provides a clean API to build browser automation tests. It relies
on &lt;a href=&quot;http://selenium.dev&quot;&gt;Selenium&lt;/a&gt;, &lt;a href=&quot;https://phantomjs.org/&quot;&gt;PhantomJS&lt;/a&gt;,
and &lt;a href=&quot;https://chromedriver.chromium.org/&quot;&gt;ChromeDriver&lt;/a&gt; as the interfacing systems to perform the “dirty” work of
coordinating requests/responses to/from the browser.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/open-source-deep-dive/hound/general-architecture.png&quot; alt=&quot;Hound&amp;#x27;s architecture&quot;&gt;&lt;/p&gt;
&lt;p&gt;This introduces a larger question, what exactly is Selenium, PhantomJS, and ChromeDriver? More importantly, in fact,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“How is browser automation performed?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Understanding how browser automation is performed provides us with a better foundation to grasp how these technologies
work and how Hound works under the hood.&lt;/p&gt;
&lt;h2 id=&quot;the-world-of-web-drivers&quot;&gt;The world of web drivers…&lt;/h2&gt;
&lt;p&gt;The key driving (pun intended) of browser automation is web drivers. But before we can understand what they are, we
should establish some basic understanding of what a driver is in general computing terms.&lt;/p&gt;
&lt;h3 id=&quot;what-are-drivers&quot;&gt;What are drivers?&lt;/h3&gt;
&lt;p&gt;Drivers are pieces of software that behave as a proxy between &lt;strong&gt;a caller&lt;/strong&gt; and &lt;strong&gt;a target.&lt;/strong&gt; Callers can be something
like the print prompt in Google Chrome or a computer peripheral. Targets can be something like the printer or computer.&lt;/p&gt;
&lt;p&gt;In general, drivers are responsible for translating the caller’s request into a given format that the target can
understand.&lt;/p&gt;
&lt;p&gt;There may be variations of a caller to the same target so each driver must be able to translate their respective
caller’s request into a common request format for the target. For instance, there are multiple types of keyboards that
can be connected to a single computer but the computer can only understand a single request format. So the respective
keyboard drivers are responsible for converting the unique keyboard’s requests into the format that the computer
accepts.&lt;/p&gt;
&lt;h3 id=&quot;back-to-web-drivers&quot;&gt;Back to web drivers&lt;/h3&gt;
&lt;p&gt;Similar to general drivers, web drivers behave as proxies for the caller (Hound) to communicate with the target (
browser). It allows the &lt;strong&gt;caller to send instructions for the browser to perform.&lt;/strong&gt; In the web development world, a
browser is also referred to as a &lt;strong&gt;user agent.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Selenium project proposed a W3C specification to guide the development of web drivers. For the rest of this
discussion, we will be relying on this specification. The specification can be
found &lt;a href=&quot;https://w3c.github.io/webdriver&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;According to the specification, there must exist a separation of concern when designing a web driver. More specifically,
there are two components to a web driver:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Local end&lt;/strong&gt; - API for developers to send requests to the browser (libraries like Selenium and Hound)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote end&lt;/strong&gt; - responsible for communicating with the browser, i.e. a browser driver (can you infer what this
means?)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In essence, a web driver is comprised of an API and a browser driver. Ideally, the API should be able to work with
different browser drivers for different browsers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/open-source-deep-dive/hound/web-driver-general-architecture.jpg&quot; alt=&quot;Web driver architecture&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The remote end must also provide an &lt;strong&gt;HTTP compliant wire protocol&lt;/strong&gt; where each endpoint maps to a command for the
browser.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means that the remote end &lt;strong&gt;relies on HTTP to communicate requests with the browser.&lt;/strong&gt; The remote end is a HTTP
server that the local end writes HTTP requests to. The remote end translates each HTTP request (based on endpoint and
method) to a command for the browser. Note that a wire protocol is a method of getting data from one point to another.
It dictates that requests should follow a given format.&lt;/p&gt;
&lt;p&gt;The specification also provides an outline for the endpoints that the remote end must make available for the local end.
This ensures standardization and ease of adoption for future browser drivers.&lt;/p&gt;
&lt;p&gt;One advantage to using a HTTP server for the remote end is that it is possible to host the remote end on a remote
machine. This means that we can delegate the job of integration testing to another machine, a process commonly known
as &lt;strong&gt;distributed testing.&lt;/strong&gt; By enabling distributed testing, the local machine is not burdened with the responsibility
of testing potentially extensive and rigorous integration tests which the machine may not support.&lt;/p&gt;
&lt;h2 id=&quot;so-how-does-selenium-work&quot;&gt;So, how does Selenium work?&lt;/h2&gt;
&lt;p&gt;Selenium implements the web driver specification (they did author it). The remote end uses
the &lt;a href=&quot;https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol&quot;&gt;JSON Wire Protocol&lt;/a&gt; as the HTTP compliant wire
protocol to communicate with the browser driver. Note that the documentation provided by Selenium (for the JSON Wire
Protocol) has been obsoleted in favor of the one defined in the specification.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/open-source-deep-dive/hound/selenium-general-architecture.jpg&quot; alt=&quot;Selenium architecturel&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;how-does-selenium-differ-from-phantomjs&quot;&gt;How does Selenium differ from PhantomJS?&lt;/h3&gt;
&lt;p&gt;PhantomJS is a &lt;strong&gt;headless browser&lt;/strong&gt; library. Headless browsers are essentially web browsers without the graphical
interfaces. Selenium, on the other hand, is a web driver. The key difference between the two is the way requests are
routed and managed (PhantomJS is a rather interesting project so Open-source Deep Dive: PhantomJS edition maybe?).&lt;/p&gt;
&lt;p&gt;However, Selenium supports headless browsers as well and more importantly, Selenium is still in active development while
PhantomJS has been archived due to a lack of active contributions.&lt;/p&gt;
&lt;h3 id=&quot;what-is-chromedriver-then&quot;&gt;What is ChromeDriver then?&lt;/h3&gt;
&lt;p&gt;ChromeDriver is a browser driver developed as part of the Chromium project. It is used by Selenium as one of the
supported browser drivers. However, Hound supports raw requests to ChromeDriver as the underlying HTTP server works the
same with or without the use of Selenium. It is an interesting project so I may explore it in another installment of
Open-source Deep Dive!&lt;/p&gt;
&lt;h2 id=&quot;hound-under-the-hood&quot;&gt;Hound: Under the hood&lt;/h2&gt;
&lt;h3 id=&quot;leveraging-browser-drivers&quot;&gt;Leveraging browser drivers&lt;/h3&gt;
&lt;p&gt;With a better understanding of how browser automation and web drivers work, we can in fact see that Hound doesn’t rely
on the entirety of Selenium (including the local end APIs). Instead, it relies on the remote end of the Selenium web
driver (along with PhantomJS and ChromeDriver) to minimize the number of “moving components” that need to be managed
while reaping the benefits of the existing technologies. Thus, it can focus on delivering a seamless API for developing
browser automation integration tests.&lt;/p&gt;
&lt;h3 id=&quot;exploring-a-basic-use-case&quot;&gt;Exploring a basic use case&lt;/h3&gt;
&lt;p&gt;We will inspect a basic use case of Hound before diving into how Hound works.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; HoundTest&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	use&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ExUnit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Case&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	use&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	hound_session&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	test &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;the truth&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, meta &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;		navigate_to&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;https://google.com&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		element &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; find_element&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;search&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;		fill_field&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(element, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Apples&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;		submit_element&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(element)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		assert &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;page_title&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Apples&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is quite a bit to unpack here. Let’s first understand the core of how a test suite with Hound is setup.&lt;/p&gt;
&lt;p&gt;First, we &lt;code&gt;use ExUnit.Case&lt;/code&gt; as Hound works hand in hand with &lt;code&gt;ExUnit&lt;/code&gt;, a built-in Elixir library for developing unit
tests. It relies on two components of &lt;code&gt;ExUnit&lt;/code&gt;: &lt;code&gt;setup&lt;/code&gt; and &lt;code&gt;on_exit&lt;/code&gt;. This allows Hound to work as expected.&lt;/p&gt;
&lt;p&gt;Then, we &lt;code&gt;use Hound.Helpers&lt;/code&gt; which, with the power of macros, imports all helper functions that are required to access
the browser session.&lt;/p&gt;
&lt;p&gt;Finally, we call &lt;code&gt;hound_session()&lt;/code&gt; which creates a new session (an instance of the browser) and initializes the setup
and tear down functionality of a Hound browser automation test.&lt;/p&gt;
&lt;p&gt;Once the core of the browser automation test is built, we can write test cases as per normal, leveraging on functions
like &lt;code&gt;navigate_to()&lt;/code&gt; and &lt;code&gt;fill_field()&lt;/code&gt; to perform browser actions. The intended behavior of these functions are easy to
understand and the documentation for them can be found &lt;a href=&quot;https://hexdocs.pm/hound/readme.html#helpers&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;breaking-it-down&quot;&gt;Breaking it down&lt;/h3&gt;
&lt;p&gt;With a basic understanding of how a test suite can be setup in Hound, we can start to decompose Hound to better
understand what makes it tick.&lt;/p&gt;
&lt;p&gt;First, we need to inspect the following file: &lt;code&gt;lib/hound/helpers.ex&lt;/code&gt; which houses the &lt;code&gt;Hound.Helpers&lt;/code&gt; module, the same
one that we &lt;code&gt;use&lt;/code&gt; in the example above.&lt;/p&gt;
&lt;p&gt;By overriding the &lt;code&gt;__using__&lt;/code&gt; macro, Hound is able to import all of the helper functions into a given file with a
single &lt;code&gt;use&lt;/code&gt; statement. This helps to minimize the boilerplate for users to get started. Macros are meta programming
constructs that inject code during compile-time. More on
macros &lt;a href=&quot;https://elixir-lang.org/getting-started/meta/macros.html&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmacro&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; __using__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([]) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  quote&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Cookie&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Dialog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Element&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Navigation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Orientation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Page&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Screenshot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SavePage&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ScriptExecution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Session&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Window&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Helpers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Mouse&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Matchers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__MODULE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Hound.Helpers&lt;/code&gt; also defines the &lt;code&gt;hound_session()&lt;/code&gt; function which relies on &lt;code&gt;setup&lt;/code&gt; and &lt;code&gt;on_exit()&lt;/code&gt; of &lt;code&gt;ExUnit&lt;/code&gt; to setup
and tear down a session between every test case.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmacro&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; hound_session&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(opts &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; []) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  quote&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    setup &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_session&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unquote&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(opts))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      parent &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      on_exit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;end_session&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(parent) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      :ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each helper function constructs a HTTP request to the browser driver server using &lt;code&gt;Hackney&lt;/code&gt; . For
instance, &lt;code&gt;navigate_to&lt;/code&gt; - which opens a given URL in the session - creates the following HTTP request:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; navigate_to&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(url, retries &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  final_url &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; generate_final_url&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(url)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  session_id &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;current_session_id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  make_req&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:post&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;session/&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;#{session_id}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/url&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, %{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;url:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; final_url}, %{}, retries)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hound rolls its own HTTP request/response management system that supports multiple retries. This can be found in
the &lt;code&gt;lib/hound/request_utils.ex&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;We have managed to break down the core functionality of Hound. There are additional interesting components to Hound that
I would like to explore as well.&lt;/p&gt;
&lt;h3 id=&quot;processes&quot;&gt;Processes&lt;/h3&gt;
&lt;p&gt;Applications are started according to standard OTP
specification (&lt;a href=&quot;https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html&quot;&gt;here&lt;/a&gt;). &lt;code&gt;lib/hound.ex&lt;/code&gt;
starts a link to &lt;code&gt;Hound.Supervisor&lt;/code&gt; which initializes two workers: &lt;code&gt;Hound.ConnectionServer&lt;/code&gt; and &lt;code&gt;Hound.SessionServer&lt;/code&gt;.
These are child processes (Hound isn’t fully up-to-date with Application convention) that the supervisor manages.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([options]) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  children &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    worker&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ConnectionServer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [options]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    worker&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SessionServer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  supervise&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(children, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;strategy:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :one_for_one&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s explore what the connection server and session server are all about next.&lt;/p&gt;
&lt;p&gt;More information on processes in Elixir &lt;a href=&quot;https://elixir-lang.org/getting-started/processes.html&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;connection-server&quot;&gt;Connection server&lt;/h3&gt;
&lt;p&gt;This process is responsible for managing the details of the browser driver and providing information to construct the
HTTP server endpoints. It stores the driver information using &lt;code&gt;Agent&lt;/code&gt; to allow the information to be accessed across
processes.&lt;/p&gt;
&lt;p&gt;More information on &lt;code&gt;Agent&lt;/code&gt; &lt;a href=&quot;https://hexdocs.pm/elixir/Agent.html&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;session-management&quot;&gt;Session management&lt;/h3&gt;
&lt;p&gt;Sessions, as mentioned earlier, refer to instances of the browser that we want to run our tests on. As Hound supports
multiple sessions across different processes, it has rolled a session management system.&lt;/p&gt;
&lt;p&gt;Session management in Hound relies on &lt;code&gt;ETS&lt;/code&gt;, a built-in storage option provided by Erlang and available in Elixir. When
the session server first starts, it creates a new &lt;code&gt;ETS&lt;/code&gt; table to hold the session information. This server is setup as
a &lt;code&gt;GenServer&lt;/code&gt; which allows it to support asynchronous and synchronous callbacks from other processes.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(state) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  :ets&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(@name, [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:named_table&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:protected&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;read_concurrency:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, state}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a session is first created by &lt;code&gt;hound_session()&lt;/code&gt;, the current process’s ID (by default, it’s the main process) is
related to the session. The process is monitored and the new session is created. Under the process ID, multiple sessions
can be created, thus allowing Hound to support multi-session testing. Each session is identified by an ID. Each session
is also assigned a name. By default, we use the session name of &lt;code&gt;:default&lt;/code&gt;. The &lt;code&gt;ETS&lt;/code&gt; table holds the following
information (mapped to JSON for illustration purposes. In reality, &lt;code&gt;ETS&lt;/code&gt; tables store tuples of data so the actual data
stored does not include any keys, just the values in the given order):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;   {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;      // Process ID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      &quot;pid&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;      // Process monitoring ref&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      &quot;ref&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      &quot;session_id&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;      // Map containing all sessions running&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      &quot;session&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;         &quot;&amp;#x3C;session_name&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&amp;#x3C;session_id&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;         ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;   }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, a session name can be assigned to the same session ID, but not the other way around (I am not too sure
why this is setup as such, more investigation would be required).&lt;/p&gt;
&lt;p&gt;With the &lt;code&gt;ETS&lt;/code&gt; table setup to manage session information, we can avoid a major problem: passing around the session ID to
various functions. If we had done so, we would have increased the overhead required when using the session ID as
functions would have to be designed to accept the session ID and we would have to devise a method of passing the session
ID around.&lt;/p&gt;
&lt;p&gt;Instead, the session ID is retrieved from the server on demand using the &lt;code&gt;current_session_id()&lt;/code&gt; function
in &lt;code&gt;lib/hound.ex&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As the current session ID is related to the calling process ID, multiple processes can have different sessions, thus,
providing multi-session testing support. This also means that if the calling process changes, the associated session
will be retrieved or a new session will be created dynamically.&lt;/p&gt;
&lt;p&gt;If a process dies - i.e. &lt;code&gt;Process.monitor()&lt;/code&gt; sends a &lt;code&gt;DOWN&lt;/code&gt; message - the session server will destroy all associated
sessions with that process asynchronously.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; handle_info&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:DOWN&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ref, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}, state) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pid &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; state[ref] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    destroy_sessions&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(pid)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:noreply&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, state}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;configurations&quot;&gt;Configurations&lt;/h3&gt;
&lt;p&gt;Configurations are managed using Elixir’s &lt;code&gt;Config&lt;/code&gt; API which uses keyword parameter lists to manage configurations.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;config &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  browser:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;firefox&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The configurations are stored as application environment variables which are retrieved by the connection server.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;driver &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; options[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:driver&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get_env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:hound&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:driver&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;selenium&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More information on the &lt;code&gt;Config&lt;/code&gt; API &lt;a href=&quot;https://hexdocs.pm/elixir/master/Config.html&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;coding-conventions&quot;&gt;Coding conventions&lt;/h3&gt;
&lt;p&gt;Other rather interesting bits of Elixir convention that Hound employs are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^&lt;/code&gt; (pin) operator&lt;/p&gt;
&lt;p&gt;The pin operator ensures that a variable, when matched during assignment, is the same as the existing variable of the
given name&lt;/p&gt;
&lt;p&gt;In Hound, this is used to ensure that the retrieved process ID of session (from the session server) is the same as
the given process ID (from argument).&lt;/p&gt;
&lt;p&gt;If the retrieved &lt;code&gt;pid&lt;/code&gt; does not match the &lt;code&gt;pid&lt;/code&gt; argument, an error is raised.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; all_sessions_for_pid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(pid) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  case&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :ets&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;lookup&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(@name, pid) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [{^pid, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_ref&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_session_id&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, all_sessions}] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; all_sessions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %{}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More information on the pin
operator &lt;a href=&quot;https://medium.com/@Julien_Corb/understand-the-pin-operator-in-elixir-a6f534d865a6&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;defdelegate&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;defdelegate&lt;/code&gt; dictates that a function’s underlying behavior is deferred to that of another function in another
module.&lt;/p&gt;
&lt;p&gt;This allows a module to house the functionality of different modules without breaking the modularity afforded by the
module system.&lt;/p&gt;
&lt;p&gt;Interestingly, the &lt;code&gt;__using__&lt;/code&gt; override in &lt;code&gt;Hound.Helpers&lt;/code&gt; can be replaced with a multitude of &lt;code&gt;defdelegate&lt;/code&gt; to the
helper functions but it would, understandably, create a lot of confusion.&lt;/p&gt;
&lt;p&gt;More information on &lt;code&gt;defdelegate&lt;/code&gt; &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.html#defdelegate/2&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;=&lt;/code&gt; (match operator) in function parameters&lt;/p&gt;
&lt;p&gt;As &lt;code&gt;=&lt;/code&gt; is the match operator in Elixir, it can be used to perform pattern matching while assigning the matched
pattern to a variable name.&lt;/p&gt;
&lt;p&gt;This is very useful when working with structures as you may not want to deconstruct the entire structure while
ensuring that arguments follow the given structure.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(%&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; user) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	IO&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;puts&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; user[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More information on the match operator &lt;a href=&quot;https://elixir-lang.org/getting-started/pattern-matching.html&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pattern matching as enums&lt;/p&gt;
&lt;p&gt;Pattern matching with atoms can be used as substitutes for typical enum behavior.&lt;/p&gt;
&lt;p&gt;An enum in Kotlin may look like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;enum&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MatchClause&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	CLASS&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;class&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	CSS&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;css selector&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	NAME&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	ID&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	ELEM&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;element&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Elixir, it can be written as such:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; match&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;class&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; match&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:css&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;css selector&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; match&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;name&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; match&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:id&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;id&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; match&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:elem&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;element&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;To conclude, Hound is a browser automation and integration testing library built on top of web driver - more
specifically, browser driver - technologies as it leverages Selenium, PhantomJS, and ChromeDriver to build a highly
abstracted and simple to use API for building integration tests.&lt;/p&gt;
&lt;p&gt;Under the hood, Hound is an intriguing project that uses fundamental constructs to build powerful internal libraries
that support complex operations.&lt;/p&gt;
&lt;p&gt;If you are interested in the topics discussed in this post, here are some additional readings:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.tutorialspoint.com/what-is-web-driver-in-selenium&quot;&gt;What is a web driver in Selenium?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://w3c.github.io/webdriver/&quot;&gt;W3C WebDriver Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/HashNuke/hound&quot;&gt;Hound GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/benoitc/hackney&quot;&gt;Hackney GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://support.smartbear.com/testcomplete/docs/testing-with/advanced/distributed/basic-concepts.html&quot;&gt;Distributed testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scotch.io/tutorials/what-is-phantomjs-and-how-is-it-used&quot;&gt;What is PhantomJS?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://source.chromium.org/chromium/chromium/src/+/master:chrome/test/chromedriver/&quot;&gt;ChromeDriver repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.testim.io/blog/browser-test-automation/&quot;&gt;Uses of browser automation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bittorrent.org/beps/bep_0003.html&quot;&gt;BitTorrent protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/ex_unit/ExUnit.html&quot;&gt;ExUnit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html&quot;&gt;Application conventions in Elixir&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/Process.html#monitor/1&quot;&gt;Process monitoring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://erlang.org/doc/man/ets.html&quot;&gt;ETS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/GenServer.html&quot;&gt;GenServer&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;callout danger&quot;&gt;&lt;p&gt;I do not condone the use of browser automation or torrenting for illegal purposes. Any links or discussions
about the mentioned subjects are purely for educational purposes and should remain as that.&lt;/p&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;p&gt;Open-source Deep Dive is a series where I pick apart open-source projects to explain the underlying concepts that power
these projects and share my findings about the project!&lt;/p&gt;</description><pubDate>Sun, 17 Jan 2021 00:00:00 GMT</pubDate></item><item><title>Elixir has opened my eyes...</title><link>https://blog.woojiahao.com/post/elixir-has-opened-my-eyes</link><guid isPermaLink="true">https://blog.woojiahao.com/post/elixir-has-opened-my-eyes</guid><description>&lt;p&gt;Functional programming (FP) is a mythical beast to the fledging developer. It can seem daunting to approach the idea of designing systems with the idea of pure functions in mind and rightfully so. I was the same a couple of years back - right when I was starting to get into computer science. Coming from object-oriented programming (OOP), FP was like trying to fit a square peg into a round hole for me. My first exposure to FP was through streams in Java 8. Then, I moved onto Kotlin and Javascript which had better “built-in” support for FP-like syntax by focusing on developing a language that has first-class functions. Finally, I approached the beast: Elixir!&lt;/p&gt;
&lt;p&gt;Learning Elixir has been a joy, honestly. It filled the gaps that Kotlin and Javascript left as they had to accommodate for OOP. In order to practice Elixir, I decided to work on Advent of Code (AoC) 2020. Working on AoC highlighted the strengths of Elixir/FP and my weaknesses in recursion and problem solving without OOP. It has also trained me to write far cleaner code without wasting crucial man-hours writing convoluted code.&lt;/p&gt;
&lt;p&gt;Recently, I was reading some Kotlin code and the most unusual thing happened: I had no idea what I was reading! I certainly understood what the code was meant to do, but I didn’t at the same time… The once elegant and easy to reason FP-esque code had become a challenge to interpret and that made me appreciate Elixir and “proper” FP more - specifically, function chaining, pattern matching, and guard clauses.&lt;/p&gt;
&lt;h2 id=&quot;function-chaining&quot;&gt;Function chaining&lt;/h2&gt;
&lt;p&gt;Function chaining is by far the easiest of the three to explain so let’s knock it out in one fell swoop.&lt;/p&gt;
&lt;p&gt;In Kotlin or Javascript, functions are chained as such:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;lst.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{ it &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{ it &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This syntax is made possible because &lt;code&gt;lst&lt;/code&gt; is a &lt;code&gt;List&amp;#x3C;T&gt;&lt;/code&gt; object and these objects have methods that provide such functionality (so really, we’re performing method calling).&lt;/p&gt;
&lt;p&gt;In Elixir, however, we do not trifle with the mundane like objects or methods. Instead, we have modules. And in these modules, we have our functions. So, in order to chain function calls, we do not rely on object method calls, instead we do something like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;lst&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Enum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;is_even&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&amp;#x26;1))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Enum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&amp;#x26;(&amp;#x26;1 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are quite literally chaining &lt;em&gt;function&lt;/em&gt; calls as opposed to chaining &lt;em&gt;method&lt;/em&gt; calls.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lst&lt;/code&gt; is passed directly as the first parameter of the first function, then the result of &lt;code&gt;Enum.filter&lt;/code&gt; is passed to the second function and so on.&lt;/p&gt;
&lt;p&gt;I like this syntax as opposed to method call chaining as it provides a clearer way of reading the code - where we do not worry about whether an object supports a given operation. We just focus on the data type of the input and pick the methods that suit this information.&lt;/p&gt;
&lt;h2 id=&quot;pattern-matching&quot;&gt;Pattern matching&lt;/h2&gt;
&lt;p&gt;Traditionally, return values or arguments are often passed in a given format (list or map, etc.) and it is the function’s responsibility to decode this structure in the function body. However, pattern matching eliminates this additional overhead by providing the necessary syntax for performing all of this decoding for us. Let’s look at several examples and contrast them against “traditional” solutions written in more OOP-oriented languages.&lt;/p&gt;
&lt;p&gt;Let’s say we declare a function that returns a tuple. This tuple represents a simple HTTP connection string: the URL and port. Let’s see how we can write this in Kotlin:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getConnString&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;193.67.13.1&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; to &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;2203&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connString &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getConnString&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; url &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connString.first&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; port &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connString.second&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s see how we would approach this in Elixir:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; get_conn_string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;193.67.13.1&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;2203&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {url, port} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; get_conn_string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A keen Kotlin developer might argue that, “Hey, since Kotlin already supports Pair unpacking, this problem is trivial right?”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wrong.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While Kotlin provides basic, single-level destructuring, it does not support far more complex ones, such as:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; big_bag&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;192.67.13.1&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;2203&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;2204&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {address, [primary_port, secondary_port]} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; big_bag&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thread lightly for brave souls have tried but failed in achieving this level of destructuring in “traditional” OOP languages.&lt;/p&gt;
&lt;p&gt;But beyond a simple application of destructuring the return values of a function, we can also use pattern matching in our function parameters.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; read_conn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({url, [primary_port, secondary_port]}) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;#{url}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;#{primary_port}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not only can we use pattern matching for destructuring parameters of a single function, we can use method overloading in conjunction with pattern matching to cater to corner cases in our parameters (more can be done with guard clauses but that is a topic I shall reserve till later on):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ex&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([instruction &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; rest], result), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ex&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(rest, result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; instruction)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ex&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([], result), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this particular example, the function &lt;code&gt;ex&lt;/code&gt; extracts the immediate instruction from the list of instructions and adds it to the result. It does so recursively until the list of instructions is empty. At that point, the function will simply return the list of instructions once again (recall that &lt;code&gt;result&lt;/code&gt; simply holds the instructions in order).&lt;/p&gt;
&lt;p&gt;This recursive function is able to halt (or encounter a stop case) because pattern matching dictates that any non-empty list will call the function again while an empty list returns the &lt;code&gt;result&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can also use pattern matching to detect when a function parameter (destructured) does not match a given format:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([name, age]), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;#{name}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;#{age}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty cool innit? The official Elixir documentation talks about pattern matching in much greater detail but I wanted to highlight the applications of pattern matching that I found interesting.&lt;/p&gt;
&lt;p&gt;Pattern matching has allowed me to write far more concise code and that has been such a wonderful feature that I sorely miss now when I work on Kotlin codebases.&lt;/p&gt;
&lt;h2 id=&quot;guard-clauses&quot;&gt;Guard clauses&lt;/h2&gt;
&lt;p&gt;Imagine we’re writing an implementation of the Fibonacci sequence in Kotlin. In order to inform the program that we have hit a base case, we would often design the function to include the base case, as such:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; fib&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(n) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (n &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; or n &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; fib&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(n &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; fib&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(n &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I don’t know about you, but the if-statement just makes the code look untidy. Instead, we can use guard clauses to spruce this up a little:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; fib&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(n) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; n &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; fib&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(n), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;do:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; fib&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(n &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; fib&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(n &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rather than embedding an if-statement inside of the function, we overload the method with a guard clause - denoted by the &lt;code&gt;when&lt;/code&gt; keyword. When the program executes, it checks every overload of the method and tries to match the patterns &lt;strong&gt;AND&lt;/strong&gt; guard clauses to ensure the right function implementation is called.&lt;/p&gt;
&lt;p&gt;This is very useful as we can expand our code to account for many base cases without polluting the core behavior of the function. This allows us to design code that scales vertically (more functions), not horizontally (more if-statements).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;&lt;del&gt;Elixir is cool and you should use it!&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;In all honesty, Elixir has taught me to value OOP more, ironically. I have realised that I am very used to the OOP way of solving problems that my fundamental problem solving skills without this hammer has become extremely dull and I am very happy that Elixir has allowed me to express my code in an elegant manner. I cannot wait to try using Elixir to build sites using Phoenix!&lt;/p&gt;</description><pubDate>Tue, 29 Dec 2020 00:00:00 GMT</pubDate></item><item><title>The truth behind software projects</title><link>https://blog.woojiahao.com/post/software-projects-truth</link><guid isPermaLink="true">https://blog.woojiahao.com/post/software-projects-truth</guid><description>&lt;p&gt;It’s 3am. You are one commit away from launching your first release of your latest idea. It’s an AI system to help
people recommend names for their pets through pictures (clearly, Spot isn’t a great name). You take a swig of coffee.
You fix the bug that has been sitting on the top of your Trello board for days now. &lt;code&gt;git add . &amp;#x26;&amp;#x26; git commit -am &quot;Fix issue where AI takes over the world&quot;&lt;/code&gt; and you are off. Time to tag this release. This AI will be a hit and pet owners
all around the globe can rejoice knowing that the arduous task of naming their pets will finally be over (now only if
you had an AI to recommend you variable names). You push the tag and head off to bed. Weeks go by and you continue
working on your revolutionary project. You add a feature that allows you to name pet rocks too. School starts. You get
swept up with a sea of assignments and presentations. Soon, your baby starts to collect dust as you scramble to finish
your assignments. Eventually, school finishes and you heave a sigh of relief. “Finally, I can add object naming too!”
you think to yourself. But when you open up the project, you realise that the spark, that allure of the project is
gone. You stare blankly at the Trello board of “To-Do” features and begin to see this project as a chore. Those new
features and promised rewrites now seem like a hassle. Those surges of dopamine you got every commit, now reduced to a
mere flicker. But this can’t happen, right? After all, this was your baby! You had spent an entire semester break
building it, raising it. It can’t all be for nothing! What will happen to the poor pet owners? You try convincing
yourself that you can power through this lack of motivation. You think to yourself, “Maybe if I just started here, I
would be able to find joy in working on this again”. But alas, no matter how hard you will yourself, you cannot find
an ounce of motivation to fix that bug, to merge that pull request, to add that feature. You sigh and start questioning
yourself. If you cannot finish a mere side project, are you even that worthy of being a developer? But eventually, you
find another side project to occupy your time. One that makes your heart race every commit. And the cycle continues.&lt;/p&gt;
&lt;p&gt;What I had just shared is - what I believe - a common narrative many developers experience. In programming, we are
often bombarded with the idea that side projects are a necessary staple of a developer - that one must have a Github
page filled to the brim with open-source contributions and personal projects to be considered a good developer. But is
it really necessary? Or are we - as a collective - creating unecessary barriers for ourselves. Is this mindset really
good for us? Or is it slowly destroying our motivation and sucking our weekends dry?&lt;/p&gt;
&lt;p&gt;In this post, I would like to explore this aspect of the industry and talk about my experiences working on side
projects and share some of my personal opinions on it. Now note, I do not claim to be a programming genius nor do I
assume that my word is gospel. I am merely sharing my observations and experiences as a developer who was mostly
self-taught. More importantly, this post is my way of performing introspection on my past five years as a developer and
how much I have grown since then.&lt;/p&gt;
&lt;h2 id=&quot;separating-the-truth-from-fiction&quot;&gt;Separating the truth from fiction&lt;/h2&gt;
&lt;p&gt;As easy as it is to denounce the notion of side projects as a parasite to one’s sanity. There are many truths and value
that can be derived from making side projets. So, I would first like to explain why I believe side projects are a
useful tool for developers.&lt;/p&gt;
&lt;p&gt;It is hard to deny that side projects can be incredibly fun to work on. When you find a project idea that you believe
in, its siren’s call is hard to resist. You’ll find yourself spending hours on end on it. Your weekends can be
engulfed by the pile of features you have planned for.&lt;/p&gt;
&lt;p&gt;When someone stars our repository. When Google Analytics reports a new user. When someone makes a pull request. When we
get a new issue. It is an undeniable fact that seeing people use what we have built is incredibly rewarding and often
times, that drives us to want to work on it more; we now have an audience of users that we cannot disappoint.&lt;/p&gt;
&lt;p&gt;Of course, many of us embark on side projects for the intrinsic rewards it presents to us. This fun is usually
derived from the prospect of learning something new. Learning how a network protocol works. Learning how a language is
used. Learning a new framework. These are all carrots-on-sticks for developers. Naturally curious, we all look for
mental stimulation and seek the next idea we can get our fingers on. Side projects serve as a great way to explore
different technologies and collaborate with others.&lt;/p&gt;
&lt;p&gt;Side projects also offer a way for us, as developers, to view how much progress we have made. Remember that simple chat
application you made when you were 16? Now look at you creating web applications from scratch or learning a whole
network protocol on your own. These side projects document your journey as a developer and it is refreshing to look
back and see how much you have grown through these projects.&lt;/p&gt;
&lt;h2 id=&quot;a-case-against-side-projects&quot;&gt;A case against side projects&lt;/h2&gt;
&lt;p&gt;However, while the benefits of side projects are bountiful, it is hard to deny the “downsides” of side projects. Now, I
use the word downsides with &lt;strong&gt;heavy&lt;/strong&gt; quotations as I do not believe that these are direct downsides of the idea of
side projects itself. Rather, I believe that the downsides to side projects are derived from the value we have placed
on them as an industry and how we - as driven individuals - have warped this perception of a side project.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I believe that side projects are unnecessarily prized and emphasised. The naturally competitive environment in tech
has caused this idea that side projects are a quintessential component of any developer’s arsenal to become overly
emphasised.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is due to this over-emphasis that many who embark on side projects often develop feelings of guilts when they are
unable to see a project through. It has caused the idea of side projects to transform from one of learning and
exploration to one of a “do-or-die” nature. Worse still, those who do not devote time to side projects may feel as
though they are losing out against others and in turn develop an obsession with trying to “catch up” to them. This also
devalues the efforts of those who try at the beginning. I believe that this boils down to the fundamental behavior of
humans: competition. We will use any - and every - metric we can get our hands on to compare ourselves against one
another. This is also why I do not agree with those who try to micro-optimise their daily lives - trying to squeeze
every second that passes to achieve optimal productivity. I was one of those who were also obsessed with ensuring that
my every waking moment was meticulously planned to ensure that my productivity remained at its peak. This was born out
of fear that the rapid advancements of this field would eventually overwhelm me and leave me in the lurch. However, the
reality is, as much as it is important to be driven, we must recognise that there is more to life than an eternal grind
to be productive. It is important that we look at the time we are spending on side projects objectively and questioning
whether we are neglecting other aspects of our life in pursuit of this “grind”.&lt;/p&gt;
&lt;p&gt;This can lead to people developing an unhealthy obsession with creating side projects and working on that “hustle”.
While many feel incredibly motivated at the beginning, those who fail to properly pace themselves will end up burnt
out. This can lead to a vicious cycle where they push themselves too hard only to feel exhausted, give up, and feel
guilty about giving up - spurring them on to try even harder. Burn out - in tech - is one of the worst things that
could happen to a developer in my honest opinion. When one’s livelihood depends on their ability to produce good code
under a time crunch, a general sense of demotivation can lead one to become careless; introducing bugs into their
system. It also diminishes one’s interest in the field and in the worst case, can drive them away from the field
entirely.&lt;/p&gt;
&lt;p&gt;There are those who also pursue the idea of side projects with the incorrect mindset. Often when I speak to beginners,
they often state that they feel this obligation to start a side project because they have noticed that others are doing
so. Some start this side project with the goal to become the number one starred repository on Github. Some dive into
one because they think that the only way to improve as a developer is to work on side projects. Some also get swept up
with the common myth that “side projects == necessity to work in a company” and end up pursuing this belief.&lt;/p&gt;
&lt;p&gt;However, what many of these individuals fail to realise is that side projects are not the only measure of a developer’s
worth. As alluring of an idea it is that a company will hire you if you have a portfolio the length of a PhD graduate,
companies are often looking to hire those who demonstrate problem-solving abilities. So what if you have made 20 APIs
before? If you fail to demonstrate the most fundamental skill a developer should possess, you won’t be able to think
critically to solve new problems. While side projects &lt;em&gt;can&lt;/em&gt; build problem-solving abilities, some may only venture
within the range of their comfort zone to try new side projects. In some cases, this could mean never trying any
“hard problems” as they do not believe that they possess the capacity to solve them on their own.&lt;/p&gt;
&lt;p&gt;It is this over-emphasis on side projects that has placed so much unnecessary pressure on new developers. I have met
many developers who have been wrapped in this worry that if they don’t start building a spectacular portfolio right
when they start, they will end up becoming a terrible developer. It is sad to see that they place this burden on
themsevles when learning to program should be a fun and enjoyable thing.&lt;/p&gt;
&lt;h2 id=&quot;so-what-now&quot;&gt;So what now?&lt;/h2&gt;
&lt;p&gt;In summary, I believe that side projects are not inherently evil. It is the warped perception of them that our industry
has created that has de-valued the true essence of them.&lt;/p&gt;
&lt;p&gt;I have been on both ends of the “side project cycle” before. I have been the naive developer who thought having
hundreds of followers on Github or thousands of stars on my projects mattered and I have also been burnt out, swamped
with school work, and dissatisfied with my perceived notion of productivity.&lt;/p&gt;
&lt;p&gt;As with anything in life, the key is balance. Understanding that side projects are not - in any way - sole markers of a
developer’s abilities is important. Having a large following on Github does not mean you are a terrific programmer and
vice versa. Learning to appreciate the learning process, rather than working on something for the potential rewards, is
an important aspect of life and moreso in this culture where developers often try to one-up one another with false
measurements of success. In the end, what you work on should matter to you. You can build something to benefit others,
I am not discouraging that, but you must bear in mind that at the end of the day, the one who benefits most from it
should be you.&lt;/p&gt;
&lt;p&gt;I think we have to look at each project objectively. “Have I learnt something about myself, this technology, or
programming in general?” If yes, then I believe that you have already benefited greatly from it. Whether or not the
project is “failed” or “incomplete”, as long as you have learnt something along the way, I do not believe that you
should belittle that effort.&lt;/p&gt;
&lt;p&gt;So go out and build something that inspires you! Work on the project that gets you excited. Explore technologies that
you are interested in. Don’t worry so much about the perceived value of the project you are embarking on. This is YOUR
journey, so enjoy it to the fullest!&lt;/p&gt;</description><pubDate>Tue, 26 May 2020 00:00:00 GMT</pubDate></item><item><title>Applications of Kotlin&apos;s delegate properties</title><link>https://blog.woojiahao.com/post/kotlin-delegate-properties</link><guid isPermaLink="true">https://blog.woojiahao.com/post/kotlin-delegate-properties</guid><description>&lt;h2 id=&quot;announcement-time&quot;&gt;Announcement time!&lt;/h2&gt;
&lt;p&gt;After a long hiatus from kMD2PDF, I revved up my engines and began to work on my latest planned feature for the
project…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;YAML support!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yes, now YAML is in the works and you can now control basic attributes of your exported document using only
&lt;a href=&quot;https://jekyllrb.com/docs/front-matter/&quot;&gt;front matter YAML.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is an incredibly big milestone as this allows anyone to quickly customise their document without having to write a
single line of Kotlin, and with another planned release to create a GUI exporter for markdown documents, this would
greatly streamline users’ experience.&lt;/p&gt;
&lt;h2 id=&quot;okay-so-what-are-delegate-properties&quot;&gt;Okay, so what are delegate properties?&lt;/h2&gt;
&lt;p&gt;kMD2PDF introduces a theming engine where you are able to change the entire color scheme of an exported document just by
specifying an attribute in code as such&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; converter &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; markdownConverter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  settings&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    theme &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Settings.Theme.DARK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;design-considerations&quot;&gt;Design considerations&lt;/h3&gt;
&lt;p&gt;Before building this system, we have to make several consideration&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How do we specify that certain attributes have different configurations depending on the theme?&lt;/li&gt;
&lt;li&gt;How do we allow changes to the theme propagate to each element such that the changes are reflected during the
document creation?&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;using-singletons&quot;&gt;Using singletons&lt;/h4&gt;
&lt;p&gt;The second inquiry is rather easy to answer, so we will tackle that issue first - we can store the &lt;code&gt;Settings&lt;/code&gt; as
&lt;a href=&quot;https://en.wikipedia.org/wiki/Singleton_pattern&quot;&gt;singleton&lt;/a&gt;, since the state of a singleton is unique and static, as
long as the settings are configured before the document is created, then the settings will be chosen during runtime and
have the exported document reflect the changes.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Settings&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; font &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; FontFamily&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;sans-serif&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; field&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;clone&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;inline&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; settings&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(configuration: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Settings&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Unit) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Settings.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(configuration)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kotlin comes with a language construct to create singletons easily - &lt;code&gt;object&lt;/code&gt; keyword (read more
&lt;a href=&quot;https://kotlinlang.org/docs/reference/object-declarations.html#object-declarations&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;This creates everything we need in a singleton but reduces all the boiler plate that would be involved with creating
the singleton, unlike other languages like &lt;a href=&quot;https://www.geeksforgeeks.org/singleton-class-java/&quot;&gt;Java.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When we update the &lt;code&gt;Settings&lt;/code&gt; singleton, the changes will reflect with the exported document since the document style is
lazily generated only up till the latest minute before it gets exported.&lt;/p&gt;
&lt;h4 id=&quot;multi-value-properties&quot;&gt;Multi-value properties&lt;/h4&gt;
&lt;p&gt;Now to tackle the hard question, how do we store multiple values in Kotlin? Ideally, what we would want with this system
is to have a single variable and have that variable store both the dark theme and light theme setting. That is, if we
had a single variable &lt;code&gt;textColor&lt;/code&gt;, we would want to be able to store both the light theme and dark theme settings inside
this variable. Depending on the current &lt;code&gt;Settings.theme&lt;/code&gt; configuration at the time where the stylesheet has to be
generated, the &lt;code&gt;textColor&lt;/code&gt; variable would return either the configuration for &lt;code&gt;DARK&lt;/code&gt; theme or &lt;code&gt;LIGHT&lt;/code&gt; theme.&lt;/p&gt;
&lt;p&gt;Traditionally, we would approach this issue using a class to store the information and have that be the end of things -
and this was indeed the approach I ended up employing due to certain limitations in that design which I’ll discuss.&lt;/p&gt;
&lt;p&gt;However, in Kotlin, there exists a language construct called
&lt;a href=&quot;https://kotlinlang.org/docs/reference/delegated-properties.html&quot;&gt;delegated properties&lt;/a&gt; where you are able to call an
object constructor to initialise a variable and provide it with a base of data. Subsequent times accessing this variable
masks the object constructor and will only allow you to access the data type specified by the delegated property. You
can think of a delegated object as an object that defaults all variable references to the given &lt;code&gt;getValue&lt;/code&gt; and
&lt;code&gt;setValue&lt;/code&gt; attributes. This effectively means that once you’ve delegated a property, you are no longer entitled to
modifying the object that created the delegate.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; kotlin.reflect.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; DelegateExample&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; internalValue &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  operator&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getValue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(thisRef: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Any&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;?, property: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;KProperty&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;*&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Internal value is ${internalValue}&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  operator&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; setValue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(thisRef: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Any&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;?, property: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;KProperty&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;*&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    internalValue &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, we have created a delegated property that when referenced as a variable (get), will return a
string. But when called with an assignment operator (set) will only accept &lt;code&gt;Int&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; by&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; DelegateExample&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// internalValue = &quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)                  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Internal value is&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                      // internalValue = &quot;10&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)                  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Internal value is 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                       // internalValue = &quot;105&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)                  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Internal value is 105&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see from, in order to instantiate a delegated property and use the features of &lt;code&gt;getValue&lt;/code&gt; and &lt;code&gt;setValue&lt;/code&gt;, we
have to set the variable with the &lt;code&gt;by&lt;/code&gt; keyword. This way, when you have variable references, it will always call the
respective &lt;code&gt;setValue&lt;/code&gt;/&lt;code&gt;getValue&lt;/code&gt; methods.&lt;/p&gt;
&lt;p&gt;Now that you’ve had a crash course with delegated properties in Kotlin, can you think of how we can apply this concept
to our current problem? To recap, we already have established a singleton to manage the configuration across all
elements - and the configuration we are most interested in is the &lt;code&gt;theme&lt;/code&gt; attribute which indicates which theme the
document will create. In that case, since the state is singular and shared across the entire program, we can create a
delegate property to hold the configuration of all the themes available, and when the time comes to generate the CSS for
the document, the delegated property is called and it will return the corresponding attribute for the specific theme
configured during the time of generation (since the document HTML/CSS are generated per call of
&lt;code&gt;MarkdownConverter#convert&lt;/code&gt; as opposed to generating them all at once).&lt;/p&gt;
&lt;p&gt;In that case, we can create the delegated property as such:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CssProperty&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; light: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;?,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; dark: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; light,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; fallback: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  operator&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getValue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(thisRef: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Any&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;?, property: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;KProperty&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;*&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    when&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Settings.theme) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      LIGHT &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; light&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      DARK &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; dark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } ?: fallback&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  operator&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; setValue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(thisRef: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Any&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;?, property: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;KProperty&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;*&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;?) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    when&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Settings.theme) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      LIGHT &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        light &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      DARK &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        dark &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, we can create a &lt;code&gt;CssProperty&lt;/code&gt; to hold the configurations required for each theme (light/dark for now) and then
when the variables are accessed, they will return the corresponding value stored depending on the current theme
configured in the settings. The &lt;code&gt;fallback&lt;/code&gt; property is a “default” for each &lt;code&gt;CssProperty&lt;/code&gt; in the event where the &lt;code&gt;light&lt;/code&gt;
or &lt;code&gt;dark&lt;/code&gt; property are both set to null.&lt;/p&gt;
&lt;p&gt;To use the &lt;code&gt;CssProperty&lt;/code&gt; class, we will use the following syntax:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; textColor &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;by&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CssProperty&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;FontFamily&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;?&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;00&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;fa&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(textColor) &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Light theme text color -&gt; #000000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Settings.theme &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Settings.Theme.DARK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(textColor) &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Dark theme text color  -&gt; #fafafa&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this provides us with such a convenient interface to modify the values of the configured properties and to quickly
change the theme settings for each element on a whim.&lt;/p&gt;
&lt;h2 id=&quot;roadblocks&quot;&gt;Roadblocks 😢&lt;/h2&gt;
&lt;p&gt;However, when attempting to create the YAML feature, I had noticed a huge flaw in the delegate property system used for
configuring the style components. Since the YAML formatting had to be rendered during runtime and as such, the YAML had
to modify the existing style which while possible using the Singleton pattern, certain components like relying on a
fallback would not be able to register the changes made. Therefore, I had to revert to using a simple class to house the
CSS properties of an element and convert the Settings singleton to be a regular object that has to be passed to each
element for the configuration to take place.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CssProperty&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; theme: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Settings&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.Theme,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; light: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; dark: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; light,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; fallback: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  var&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; when&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(theme) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      LIGHT &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; light&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      DARK &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; dark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } ?: fallback&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(input) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      light &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; input&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      dark &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; input&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then in order for the converter to apply the changes of the YAML to the document being generated, we iterate over every
element within the style and apply the changes accordingly.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Element&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;updateStyles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(input: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;?, update: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Element&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.(T) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Unit) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  input?.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { e &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; e.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(it)  } }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The lesson learnt here is that while a structure might look good on paper and work for a specific use case, this might
not always be the case and this can result in rewriting of the codebase. I was lucky that the codebase was one that I
was very familiar with and I could afford the rewrite to get this new feature up and running. However, I would not
always be so lucky and might encounter a codebase that might take too long to rewrite.&lt;/p&gt;</description><pubDate>Sat, 13 Jul 2019 00:00:00 GMT</pubDate></item><item><title>Porting to FlexMark</title><link>https://blog.woojiahao.com/post/porting-flexmark</link><guid isPermaLink="true">https://blog.woojiahao.com/post/porting-flexmark</guid><description>&lt;p&gt;kMD2PDF now finally uses &lt;a href=&quot;https://github.com/vsch/flexmark-java&quot;&gt;FlexMark&lt;/a&gt; as the back end for the markdown to html
conversion. This is a big moment as now a lot more flexibility has been introduced for the library and that means more
features.&lt;/p&gt;
&lt;p&gt;Following my promise of making smaller and more frequent release updates, this port has ushered in version &lt;code&gt;0.2.1&lt;/code&gt; of
kMD2PDF and I’m really excited!&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Backend library using flexmark&lt;/li&gt;
&lt;li&gt;Unit testing framework set up for testing node rendering&lt;/li&gt;
&lt;li&gt;Task list items now supported&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;original-design&quot;&gt;Original design&lt;/h2&gt;
&lt;p&gt;Originally, the library used commonmark to handle &lt;code&gt;.md&lt;/code&gt; to &lt;code&gt;.html&lt;/code&gt; conversions, but it was severely limited as the
number of useful extensions was severely lacking and it resulting in a terrible codebase. However, with FlexMark, this
problem is alleviated as it has all the features I need.&lt;/p&gt;
&lt;h2 id=&quot;hiccups&quot;&gt;Hiccups&lt;/h2&gt;
&lt;p&gt;There was a slight hiccup with the port as the &lt;code&gt;.html&lt;/code&gt; to &lt;code&gt;.pdf&lt;/code&gt; library,
&lt;a href=&quot;https://github.com/flyingsaucerproject/flyingsaucer&quot;&gt;flyingsaucer&lt;/a&gt; would not accept the HTML output produced by
FlexMark. So I had to make use of Jsoup to parse the output of FlexMark to become valid XML that the flyingsaucer
library would accept.&lt;/p&gt;
&lt;p&gt;Another issue faced is the node renderers and visitors. In commonmark, these node renderers were a single class that
would be added the parser
(seen &lt;a href=&quot;https://github.com/atlassian/commonmark-java#customize-html-rendering&quot;&gt;here&lt;/a&gt;) and visitors would be accepted
after the document is parsed
(seen &lt;a href=&quot;https://github.com/atlassian/commonmark-java#use-a-visitor-to-process-parsed-nodes&quot;&gt;here&lt;/a&gt;). This made it really
easy to create custom node renderers and visitors which were used for figure generation and table of contents
processing. However, with FlexMark, due to the increase in flexibility, the overhead for creating both increased as
well and this resulted in requiring a parsing extension to be created, which would create a custom NodeRenderingFactory
which in turn be responsible for creating custom NodeRenderers to render the needed node, which in this case was the
figure elements. Whilst this may seem all complicated, it was actually outlined in their sample
&lt;a href=&quot;https://github.com/vsch/flexmark-java/blob/master/flexmark-java-samples/src/com/vladsch/flexmark/samples/NodeRendererSample.java&quot;&gt;repository&lt;/a&gt;
where I was able to successfully create the figure renderer
&lt;a href=&quot;https://github.com/omnius-project/kMD2PDF/tree/master/src/main/kotlin/com/github/woojiahao/modifiers/figure&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The table of content processor was similar in nature. Due to the increased flexibility offered by FlexMark, additional
steps had to be taken to create a visitor to properly create the table of contents. This highlighted the idea that
developing flexible software would often entail having to increase the overhead of the software because it just takes
that many extra steps to provide that flexibility.&lt;/p&gt;
&lt;h2 id=&quot;unit-testing-the-dom&quot;&gt;Unit testing the DOM&lt;/h2&gt;
&lt;p&gt;I also worked on attempting to create a system to unit test the node rendering aspect of the library since there can be
a lot of edge cases involved with markdown and it might be useful to have an automated system to be able to ensure that
the code is reliable and performs within my range of expectation.&lt;/p&gt;
&lt;p&gt;I tried to design this API to be as seamless as possible, reducing the moving parts exposed to the user so that they
would not have to fiddle with too many configurations to get it working. What I came up with was rather interesting.
To ensure that the rendering was correct, I had to first find a way to test that the converted markdown file would
produce a certain result. To do so, I exposed the HTML conversion process of &lt;code&gt;MarkdownConverter&lt;/code&gt; to be able to hook
into this using the API.&lt;/p&gt;
&lt;p&gt;The essence of the API is to compare the processed HTML and an expected HTML input using Jsoup to ensure that the they
are the same. This required some basic recursion to assert that every single node matched.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; assertMarkdown&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(folder: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, file: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(file.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;indexOf&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;File should not include extensions as they are added within the method&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; markdownFileName &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;$file&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.md&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; htmlFileName &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;$file&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.html&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; markdownFile &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getResource&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(folder, markdownFileName)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; htmlFile &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getResource&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(folder, htmlFileName)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; converter &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; setupConverter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(markdownFile)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; expectedDocument &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; parseDocument&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(htmlFile.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;readText&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; actualDocument &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    parseDocument&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(converter.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;generateBody&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getElementsByClass&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;first&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // Ensure that they both have the same number of children&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  assertEquals&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(expectedDocument.childCount, actualDocument.childCount)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // Ensure that they both have the same set of elements&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; expectedDocumentBody &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; expectedDocument.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; actualDocumentBody &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; actualDocument.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  expectedDocumentBody.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;zip&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(actualDocumentBody).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;compare&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(it.first, it.second) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the markdown file will be the actual output produced by the library whilst the html file represents the
expected output.&lt;/p&gt;
&lt;p&gt;This was the bulk of the API, with the recursive function looking like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; compare&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ex: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Element&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ac: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Element&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  assertElementEquals&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ex, ac)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (ex.childCount &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; until ex.childCount).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      compare&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ex.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;child&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(it), ac.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;child&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(it))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows the users to simply execute the &lt;code&gt;assertMarkdown()&lt;/code&gt; function, providing the resource folder and resource name
of the markdown file and html file. This would set in motion an automated set of testing to ensure that every aspect
of the generated markdown file would produce the appropriate html.&lt;/p&gt;
&lt;p&gt;One limitation that is present with the API is that the file name of the markdown file and html file would have to be
the same, otherwise the assert function would fail. That said, it also encourages for developers trying to use the API
to always stick to the same name for their markdown and html file, which reduces confusion.&lt;/p&gt;</description><pubDate>Mon, 08 Apr 2019 00:00:00 GMT</pubDate></item><item><title>Lessons on software release</title><link>https://blog.woojiahao.com/post/lessons-on-software-release</link><guid isPermaLink="true">https://blog.woojiahao.com/post/lessons-on-software-release</guid><description>&lt;p&gt;Oh boy, I screwed up bad, like &lt;em&gt;really&lt;/em&gt; badly. Ok ok, let’s go back and see where it all began. I’ve learnt countless
lessons from this and I hope you (reader) will too if you’re developing your own software.&lt;/p&gt;
&lt;h2 id=&quot;story-time&quot;&gt;Story time!&lt;/h2&gt;
&lt;p&gt;2 months ago, I embarked on a journey to write a markdown to PDF converter, called
&lt;a href=&quot;https://omnius-project.github.io/kMD2PDF&quot;&gt;kMD2PDF&lt;/a&gt;. The initial architecture was developed such that:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;.md file -&gt; .html file + .css styling -&gt; .pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to facilitate this system, I used 2 libraries:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;commonmark-java&lt;/code&gt; - this facilitated with the &lt;code&gt;.md -&gt; .html&lt;/code&gt; conversion&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flyingsaucer&lt;/code&gt; - this facilitated with the &lt;code&gt;.html -&gt; .pdf&lt;/code&gt; conversion&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In between, I used my own code to create a style DSL to generate the CSS styling. This system worked nicely as I was
able to create an easy to use API for developers using this library.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; document &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MarkdownDocument&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;~/Desktop/README.md&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; convert &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; markdownConverter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    document&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(document)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  converter.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;convert&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;failure-to-research&quot;&gt;Failure to research&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;However,&lt;/strong&gt; I made several big oversights. I failed to plan that the libraries I used were severely limited in what
they could offer. For instance, &lt;code&gt;commonmark-java&lt;/code&gt; does not support task list items, even as an extension and in order
to implement this feature, I had to create a custom &lt;code&gt;NodeRenderer&lt;/code&gt; that would convert bullet lists to task list items
if necessary. Then I realised that because I overrode the default rendering behavior of the bullet lists, I no longer
could create nested lists, so I had to remedy that myself and soon, the project became a bunch of band-aids stuck on
top of the library and it caused the project to steer into a direction of just bug fix upon bug fix, as I attempted to
introduce features into a tightly-coupled system. This made for an incredibly hard time working on the library as I was
de-motivated to implement features since they would result in a mess.&lt;/p&gt;
&lt;p&gt;Worst still, as I researched more libraries for handling markdown parsing, I noticed that there were libraries like
Flexmark that &lt;em&gt;did&lt;/em&gt; provide the support for the features I wanted such as task lists without requiring a lot of hacky
work to be performed to the existing library.&lt;/p&gt;
&lt;p&gt;Similarly, a big hurdle I had to cross with flyingsaucer was getting HTML5 xml code to render as the library required
only XML or XHTML documents. This was a huge bottleneck because now some elements render incorrectly and others
require even longer HTML that isn’t always necessary. That’s where I discovered OpenHTMLToPDF, which had a similar API
to flyingsaucer but it allowed for HTML5 code and it doesn’t constrict users by forcing them to use XHTML (for the
uninitiated, XHTML is a stricter form of HTML, where single-enclosed tags are not permitted, rather, every tag must be
closed off with an ending tag).&lt;/p&gt;
&lt;p&gt;This failure to plan ahead and research properly made my life hell as I spent most of my time fixing issues I created
for myself.&lt;/p&gt;
&lt;h3 id=&quot;over-committing&quot;&gt;Over committing&lt;/h3&gt;
&lt;p&gt;Another issue I had stupidly created for myself is over-committing to creating a huge feature push. Initially, after
releasing version 0.1.2, I started work on version 0.2.0 - where many new features would come, along with a set of
changes to the existing API to improve the lives of developers. But… that’s where I failed to realise that I had
bitten off more than I could chew.&lt;/p&gt;
&lt;p&gt;For an entire month, I focussed my efforts on trying to make version 0.2.0 feature complete. And within this period of
time, the stable version of the library never once got updated. This spelt bad news for those who are using 0.1.2 as
they are waiting for over a month for a newer library, whilst they’re stuck with a bug-filled library. It also meant
that I would burn out quickly working on the library as I tried pushing to complete the features by an arbitrary
deadline.&lt;/p&gt;
&lt;p&gt;This caused me to be extremely stressed when users of the library would hound me for changes. However, during this
month, I did learn a lot about Kotlin and software development so it wasn’t a complete waste of time. I just know it
could have been so much better and smoother.&lt;/p&gt;
&lt;p&gt;This is where I also begin to see the value of Agile development, where we should break up the development into
deliverables across weeks to reduce the workload and to improve the end user experience.&lt;/p&gt;
&lt;h3 id=&quot;no-testing&quot;&gt;No testing&lt;/h3&gt;
&lt;p&gt;An area lacking in the library is unit testing. As the markdown can have many corner cases, it’s hard to cater to each
of these. The lack of unit tests meant that the bugs I encounter are always by accident, rather than the result of
methodical checking and testing to ensure that nothing slips the radar.&lt;/p&gt;
&lt;p&gt;Backtracking to unit test everything is also a pain as by this point, I would have forgotten about some of the classes.&lt;/p&gt;
&lt;h2 id=&quot;learning-points&quot;&gt;Learning points&lt;/h2&gt;
&lt;p&gt;So what exactly did I take away from this experience and how will I be improving my approach. I’ve learnt to be more
methodical with my research before starting a project, I should carefully scope for the best libraries and options
available for the job. I’ve also come to realise just how key portioning work and creating frequent deliverables is to
developing good software. Finally, I’ve learnt to use TDD or at least, unit test my code as I write them, rather than
leaving it till the last minute.&lt;/p&gt;
&lt;p&gt;So what exactly does this mean for kMD2PDF? Well, I’ll begin by announcing several changes to my workflow. First and
foremost, I’ll be porting my codebase to use Flexmark and OpenHTMLToPDF over the next few releases, so that’s exciting!
Secondly, I’ll shorten the release cycle to have new versions of the library be released every 2 weeks where the
versioning will go from &lt;code&gt;0.2.0&lt;/code&gt; to &lt;code&gt;0.2.1&lt;/code&gt; etc. Each release will contain a few features and fixes and the goal is to
make the library stable and ready to use as frequently as possible. Lastly, I’ll begin to rolling out a suite of unit
tests for the codebase. I’ll adopt TDD in my workflow and hopefully, I can reach &gt; 80% code coverage before version
1.0.0.&lt;/p&gt;
&lt;p&gt;Whilst I’m incredibly frustrated about my set backs, I will not allow them to hinder the development and progress of
the library and with a new found resolve to achieve better things, I’ll be taking on each new challenge with pride. I
have also greatly enjoyed the past month learning various skills and practicing Kotlin.&lt;/p&gt;
&lt;p&gt;If you’re curious about the library, it can be found &lt;a href=&quot;https://github.com/omnius-project/kMD2PDF&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;</description><pubDate>Wed, 03 Apr 2019 00:00:00 GMT</pubDate></item><item><title>An investigation into generics in Java</title><link>https://blog.woojiahao.com/post/java-generics</link><guid isPermaLink="true">https://blog.woojiahao.com/post/java-generics</guid><description>&lt;p&gt;Generics was a feature introduced in &lt;a href=&quot;https://en.wikipedia.org/wiki/Generics_in_Java&quot;&gt;Java 5&lt;/a&gt; and it has changed how
Java developers write code.&lt;/p&gt;
&lt;p&gt;This article will be discussing some of the things I’ve picked up as I dug into generics in Java.&lt;/p&gt;
&lt;h2 id=&quot;uses-of-generics&quot;&gt;Uses of generics&lt;/h2&gt;
&lt;h3 id=&quot;pre-generics-era&quot;&gt;Pre-generics era&lt;/h3&gt;
&lt;p&gt;Imagine you wish to create a container to store an object that can be of any type, pre-generics, you would need to do
something like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Container&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  private&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Object obj;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Object &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getObj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; obj;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; setObj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Object &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;obj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.obj &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; obj;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Container container &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Container&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setObj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;((String) container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getObj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Prints &quot;Hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setObj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;((Integer) container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getObj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Prints 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, this is not type safe as you can put anything into the Container and have it spit out something
because the Container doesn’t care for the type of the inputs. You can get around this lack of type safety by giving
the class type of the intended inputs into the Container constructor and check that against the inputs, but that will
be extra code for something that seems so logical.&lt;/p&gt;
&lt;h3 id=&quot;generics-era&quot;&gt;Generics era&lt;/h3&gt;
&lt;p&gt;With generics, you can now create the Container with type safety built in and no more casting.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Container&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  private&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; T obj;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; T &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getObj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; obj;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; setObj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(T &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;obj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.obj &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; obj;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Container&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; container &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Container&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setObj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getObj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Prints &quot;Hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;container.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setObj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Does not compile because container can only receive Strings&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;whats-going-on&quot;&gt;What’s going on?&lt;/h2&gt;
&lt;p&gt;This was a question I had asked a lot prior to reading up, because it was such a mysterious process that I could somehow
enforce type safety just with this construct.&lt;/p&gt;
&lt;p&gt;The type safety generics offer is limited to just &lt;strong&gt;compile time&lt;/strong&gt;, this is because of a process
called &lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/generics/erasure.html&quot;&gt;Type Erasure&lt;/a&gt; where the generic type
is removed during runtime. This is done in an effort to ensure backward compatibility to pre-generic code.&lt;/p&gt;
&lt;p&gt;This not only means that the type safety isn’t extended to runtime, it also means that any operations requiring the use
of this generic type at runtime is not permitted because the type will be erased by that point. For example:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(T.class); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// This does not work!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Java isn’t able to recognize the data type of &lt;code&gt;T&lt;/code&gt; during runtime thanks to erasure and thus this line throws and
exception. This is especially troubling as you might want to be able to cast the data types from one generic type to
another, but this is not possible.&lt;/p&gt;
&lt;p&gt;This state can also be referred to as generics being non-reified, meaning, it is not present during runtime.&lt;/p&gt;
&lt;h2 id=&quot;kotlin-to-the-rescue&quot;&gt;Kotlin to the rescue!&lt;/h2&gt;
&lt;p&gt;Since Kotlin is based off the JVM, it also inherits this type erasure behavior of generic types, which means behavior
with generics you see in Java will be the same in Kotlin. However, Kotlin offers a means of enabling a generic type to
be preserved during runtime, thus removing the “burden” imposed on it.&lt;/p&gt;
&lt;h3 id=&quot;reified-generic-types--inline-functions&quot;&gt;Reified generic types + inline functions&lt;/h3&gt;
&lt;p&gt;In Kotlin, the &lt;a href=&quot;https://kotlinlang.org/docs/reference/inline-functions.html&quot;&gt;&lt;code&gt;inline&lt;/code&gt;&lt;/a&gt; keyword, makes it so the function
is not expanded into a separate object but rather “copy-pasted” into the call site of the function, thus allowing some
interesting behavior to occur.&lt;/p&gt;
&lt;p&gt;One such intriguing behavior is allow generic types to be reified, or retained at runtime. Because the function is now
inline, the generic type given to the function can be preserved, thus, allowing you to access the generic type
information during runtime.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(T::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.java)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Generics are an interesting construct with a lot of thought put into designing them.&lt;/p&gt;
&lt;p&gt;Some articles that might peak your interest:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters&quot;&gt;&lt;strong&gt;reified&lt;/strong&gt; keyword in Kotlin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/generics/erasure.html&quot;&gt;Type Erasure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oracle.com/technetwork/articles/java/juneau-generics-2255374.html&quot;&gt;Generics: How They Work And Why They Are Important&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Mon, 26 Nov 2018 00:00:00 GMT</pubDate></item><item><title>Familiarising yourself with lambdas in Kotlin</title><link>https://blog.woojiahao.com/post/kotlin-lambdas</link><guid isPermaLink="true">https://blog.woojiahao.com/post/kotlin-lambdas</guid><description>&lt;p&gt;Kotlin is a language that was built on top of the JVM and what really sets it apart from Java is the emphasis on
&lt;strong&gt;functions being a first-class construct&lt;/strong&gt;, meaning many fancy things like lambdas are directly available to Kotlin
developers without having to include bulky constructs like the concept of &lt;em&gt;functional interfaces&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-are-lambdas&quot;&gt;What are lambdas?&lt;/h2&gt;
&lt;p&gt;In my article on &lt;a href=&quot;https://woojiahao.github.io/Diving-Into-Streams/&quot;&gt;Diving Into Streams,&lt;/a&gt; I explained how lambdas
were this miraculous constructs in Java that removed a lot of the boilerplate required when passing behavior from one
method to another.&lt;/p&gt;
&lt;p&gt;However, this definition was really under the assumption of pure Java. Lambdas, as a whole, are a mathematical concept.
In programming, a lambda can be seen as a “portable” function or a piece of behavior that can be passed around and used
accordingly.&lt;/p&gt;
&lt;h3 id=&quot;then-what-are-functions&quot;&gt;Then, what are functions?&lt;/h3&gt;
&lt;p&gt;Functions are simply pieces of behavior that take in some input (or none at all) and return some output (or none at all)
,
this is very much the same as the mathematical concept it is based off of.&lt;/p&gt;
&lt;h2 id=&quot;a-case-for-lambdas&quot;&gt;A case for lambdas&lt;/h2&gt;
&lt;h3 id=&quot;scenario&quot;&gt;Scenario:&lt;/h3&gt;
&lt;p&gt;Say you were working in a performance-critical situation and you just discovered that there is a major memory issue with
a function and it is causing some major performance drawbacks and you want to see how long it takes to benchmark and
fix this issue.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“No biggie, I can take the time before and after the execution and check how long that took to benchmark the function”&lt;/em&gt;
would be something you are thinking to yourself and that would be true in a simple case like ours.&lt;/p&gt;
&lt;p&gt;You begin to write some code to test this function:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; foo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(upper: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;): &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sum &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;upper) sum &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sum&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(main: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; before &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; System.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;foo returns: ${&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10000&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;)}&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; after &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; System.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;foo took ${after &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; before}ms to run&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Awesome! It worked, you can now go on your merry way and fix the bug. Then you manager comes around and tells you yet
&lt;em&gt;another&lt;/em&gt; performance issue was found and you think &lt;em&gt;“Eh, this is kind of tedious to redo so I guess I could copy-paste
the code I made earlier”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Now, would you be able to continually repeat this if you suddenly had a whole class of functions that needed to be
tested?&lt;/p&gt;
&lt;h3 id=&quot;lambdas-to-the-rescue&quot;&gt;Lambdas to the rescue!&lt;/h3&gt;
&lt;p&gt;Going back to how I mentioned how a lambda is &lt;code&gt;a &quot;portable&quot; function or a piece of behavior that can be passed around and used accordingly.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In this scenario, we ideally, would want to have a function that can time &lt;strong&gt;any&lt;/strong&gt; function with a method signature like
&lt;code&gt;foo()&lt;/code&gt; and this timing function would not need to know anything about the function it receives, all it needs to know
it that it should calculate the time before and after this function took to run and print that out, nicely formatted.&lt;/p&gt;
&lt;p&gt;Some basic pseudo-code would look like this:&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Details&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;&lt;ol&gt;&lt;li&gt;Name of the function&lt;/li&gt;&lt;li&gt;Function to be timed&lt;/li&gt;&lt;/ol&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Output&lt;/td&gt;&lt;td&gt;None, this function will make use of a side effect&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Steps&lt;/td&gt;&lt;td&gt;&lt;ol&gt;&lt;li&gt;Take the time before running the function&lt;/li&gt;&lt;li&gt;Run the function&lt;/li&gt;&lt;li&gt;Take the time after running the function&lt;/li&gt;&lt;li&gt;Print out the difference between the before and after, this will be total time it took to for the function to run&lt;/li&gt;&lt;/ol&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h4 id=&quot;defining-structure&quot;&gt;Defining structure&lt;/h4&gt;
&lt;p&gt;In Kotlin, in order to declare a lambda, you have to declare a &lt;em&gt;function type&lt;/em&gt;, or some kind of contract for the
functions to be passed to follow. To simplify things, all the memory leaks that have surfaced all take in exactly 1 Int
input and return an Int, so the function type for this case would look something like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;func: (&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note how the function type is literally just the method signature of a potential function without the parameter names.
As mentioned previously, these function types are merely just contracts, it defines what a function to be passed in
should
look like, it does not dictate what the inputs will be used for (generally what the parameter names represent) nor does
it dictate the specific behaviors of this function.&lt;/p&gt;
&lt;h4 id=&quot;creating-the-timing-function&quot;&gt;Creating the timing function&lt;/h4&gt;
&lt;p&gt;Now that we have the general structure of the function we want to be able to time, we can then proceed with declaring
the
function body of this timer.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; functionTimer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(name: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, upper: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, func: (&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; before &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; System.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; returned ${&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;(upper)}&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; after &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; System.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; took ${after &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; before}ms to run&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, this function’s body is very much the same as the original method of timing the function in the &lt;code&gt;main&lt;/code&gt;
method. However, whilst there were some similarities, the benefits of creating a specialized function for timing is as
follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Modularity&lt;/strong&gt; - your code is now modular and can be reused if needed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexible&lt;/strong&gt; - because this is a function, you can apply consistent changes to the timing and the changes made will
be reflected in any function timed by this function made&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Abstraction&lt;/strong&gt; - a new user of your codebase does not need to think about how a function is timed, all they need to
know is how to call this timing function and they know that this function will help to time and do everything for
them&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistency&lt;/strong&gt; - we can remove the &lt;code&gt;upper&lt;/code&gt; argument and apply a consistent argument to be passed to &lt;code&gt;func&lt;/code&gt; so that
the timing is not skewed by changes in the upper, thus ensuring a degree of consistency&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;timing-things&quot;&gt;Timing things&lt;/h4&gt;
&lt;p&gt;With the newly made timing function, we can then begin to time how long each function took in our class. Let’s begin
with
the first function we tested, which simply added a bunch of numbers from 1 up till an upper value.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(args: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  functionTimer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sum &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;it) sum &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    sum&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What we have used is the lambda syntax Kotlin provides. We declare the arguments of the &lt;code&gt;functionTimer&lt;/code&gt; function as per
usual, but we then use &lt;code&gt;{}&lt;/code&gt; which houses the body of the function. We also use the &lt;code&gt;it&lt;/code&gt; keyword, to refer to the one and
only input this lambda receives, which we can assume would be the upper limit (in this case, &lt;em&gt;10000&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Another thing to note is we omit the &lt;code&gt;return&lt;/code&gt; keyword from the lambda body even though the function type specifies that
each function has to return an &lt;code&gt;Int&lt;/code&gt;. We simply put the value to be returned on a line of its own and Kotlin is clever
enough to know to return this value.&lt;/p&gt;
&lt;p&gt;Now, we can extend this function to work with any other function that takes in a single Int input and return an Int…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;functionTimer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;multiply&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;it) result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;functionTimer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;wacky&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;it).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { num &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; num &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Sample output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;add returned 50005000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;add took 1ms to run&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;multiply returned 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;multiply took 0ms to run&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;wacky returned 1501500&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;wacky took 58ms to run&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see how flexible we can make this timer be, taking in all sorts of functions and timing them.&lt;/p&gt;
&lt;h4 id=&quot;timing-existing-functions&quot;&gt;Timing existing functions&lt;/h4&gt;
&lt;p&gt;Sometimes, you might not want to rewrite a long function just to time it, and that is perfectly fine, you can pass a
reference to an existing method for it to be run as such:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;functionTimer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Lambdas are far more than just useful for timing stuff, it is extremely versatile and Kotlin uses them extensively
throughout their language, in Collections to APIs that leverage off the design of lambdas.&lt;/p&gt;
&lt;p&gt;Some resources for further reading:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kotlinlang.org/docs/reference/lambdas.html&quot;&gt;Kotlin documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.baeldung.com/kotlin-lambda-expressions&quot;&gt;Baeldung&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><pubDate>Sun, 28 Oct 2018 00:00:00 GMT</pubDate></item><item><title>Diving into (Java) streams</title><link>https://blog.woojiahao.com/post/diving-into-streams</link><guid isPermaLink="true">https://blog.woojiahao.com/post/diving-into-streams</guid><description>&lt;h2 id=&quot;what-are-streams&quot;&gt;What are streams?&lt;/h2&gt;
&lt;p&gt;Streams was introduced in Java 1.8 and it had completely changed how we write code. The majority of what I will be discussing will be what I have learnt from watching &lt;a href=&quot;https://www.youtube.com/watch?v=1OpAgZvYXLQ&amp;#x26;t=6985s&quot;&gt;this talk&lt;/a&gt; by Venkat Subramaniam. His talk was what had originally got me into using streams and the concept of lambdas.&lt;/p&gt;
&lt;h2 id=&quot;lets-revise&quot;&gt;Let’s revise&lt;/h2&gt;
&lt;h3 id=&quot;how-do-we-implement-a-lambda-in-java&quot;&gt;How do we implement a lambda in Java?&lt;/h3&gt;
&lt;p&gt;Lambdas are simple constructs with very powerful use cases in Java and many other languages. Most commonly, lambdas enable the everyday programmer to reduce their clunky &lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html&quot;&gt;anonymous inner classes&lt;/a&gt; into simple one-liners. It can also be used to pass methods around between methods without having to redeclare these method over and over again.&lt;/p&gt;
&lt;p&gt;The common components that make up a lambda in Java are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A functional interface&lt;/li&gt;
&lt;li&gt;A method that matches the signature of the method in the functional interface&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;what-is-a-functional-interface&quot;&gt;What is a functional interface?&lt;/h3&gt;
&lt;p&gt;A functional interface is an interface that contains a single method.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; StringOp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  String &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;perform&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (String &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;using-a-lambda&quot;&gt;Using a lambda:&lt;/h3&gt;
&lt;p&gt;Code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; StringOp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  String &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;perform&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (String &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LambdaDemo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    StringOp operation &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; in &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; StringBuilder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(in).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reverse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(operation.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;perform&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;dlroW olleH&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, I created a functional interface (&lt;code&gt;StringOp&lt;/code&gt;), declared an instance of that functional interface (&lt;code&gt;operation&lt;/code&gt;) and gave it’s definition all in one line using a lambda.&lt;/p&gt;
&lt;p&gt;The core syntax of the lambda is as such:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(parameters) -&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  actions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In cases where there is only 1 parameter, the parantheses can be omitted, as seen in the example, and if the method body a single line, you can also omit the curly braces.&lt;/p&gt;
&lt;p&gt;If lambdas did not exist, I would have to declare the method like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;StringOp operation &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; StringOp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; String &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;perform&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (String &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; StringBuilder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(in).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reverse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;operation.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;perform&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These are just simple examples of what lambdas are capable of, there a many more uses for them and you can check out a more comprehensive guide here: &lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html&quot;&gt;https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;starting-streams&quot;&gt;Starting streams&lt;/h2&gt;
&lt;p&gt;I will first begin by showing an example of a typical program and then showing the power of streams and how they can be used to simplify your work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Write a program to print out all numbers that are multiples of a given number within a given range.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Traditional Solution:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Solution&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; printMultiples&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; multiple&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; upper&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; upper; i&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; multiple &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(i);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    printMultiples&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Streams Solution:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Solution&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; printMultiples&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; multiple&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; upper&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    IntStream&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;rangeClosed&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, upper)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; multiple &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(System.out&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;println);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    printMultiples&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, both methods produce the same output, however, the latter is a lot neater than the former. Not only is the solution simpler to understand than the solution that introduces loops and if statements, it is a lot easier to read and understand.&lt;/p&gt;
&lt;h2 id=&quot;explanation&quot;&gt;Explanation:&lt;/h2&gt;
&lt;p&gt;The reason why methods like &lt;code&gt;.filter(i -&gt; i % multiple == 0)&lt;/code&gt; works is due to the use of functional interface as mentioned previously. According to the Java documentation on streams, &lt;code&gt;.filter()&lt;/code&gt; receives a &lt;code&gt;Predicate&lt;/code&gt; interface as a parameter.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Represents a predicate (boolean-valued function) of one argument.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means in order to create a lambda that receives one argument and returns a boolean condition.&lt;/p&gt;
&lt;h2 id=&quot;method-references&quot;&gt;Method references&lt;/h2&gt;
&lt;p&gt;Another unusual syntax you might have noticed is this &lt;code&gt;forEach(System.out::println)&lt;/code&gt;, you might be scratching your head and wondering that this &lt;code&gt;::&lt;/code&gt; symbol is doing. Well, it is known as a &lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html&quot;&gt;method reference&lt;/a&gt;. The core idea with method references would be as Mr. Venkat put it&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Since the value is a simple pass over, you can use a method reference.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To illustrate this, let’s see how you would use the &lt;code&gt;.forEach()&lt;/code&gt; method normally:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] menu &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Pizza&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Cola&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Salad&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Arrays.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;asList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(menu)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stream&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(menuItem &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(menuItem));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Pizza&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Cola&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Salad&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, for &lt;code&gt;forEach()&lt;/code&gt;, the &lt;code&gt;menuItem&lt;/code&gt; argument you receive is simply being passed onto the &lt;code&gt;System.out.println&lt;/code&gt; method call, and since no other modification is being made to this &lt;code&gt;menuItem&lt;/code&gt; value, you can use a method reference to &lt;code&gt;System.out.println&lt;/code&gt; to shorten to code.&lt;/p&gt;
&lt;p&gt;In this particular instance, since &lt;code&gt;println&lt;/code&gt; is a static method of the &lt;code&gt;System.out&lt;/code&gt; object, the method reference will be a reference to a static method, which means the syntax would simply be having the &lt;code&gt;object name&lt;/code&gt; followed by the &lt;code&gt;::&lt;/code&gt; symbol and then the &lt;code&gt;target method name&lt;/code&gt;.&lt;/p&gt;</description><pubDate>Sun, 08 Apr 2018 00:00:00 GMT</pubDate></item></channel></rss>