<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: C. Plug</title>
    <description>The latest articles on DEV Community by C. Plug (@clpsplug).</description>
    <link>https://dev.to/clpsplug</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F43590%2F9796aed2-75e3-499d-b898-319d3c633737.jpeg</url>
      <title>DEV Community: C. Plug</title>
      <link>https://dev.to/clpsplug</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/clpsplug"/>
    <language>en</language>
    <item>
      <title>How do you debug a Python script that crashes Python itself?</title>
      <dc:creator>C. Plug</dc:creator>
      <pubDate>Tue, 02 May 2023 17:08:36 +0000</pubDate>
      <link>https://dev.to/clpsplug/how-do-you-debug-a-python-script-that-crashes-python-itself-4hpc</link>
      <guid>https://dev.to/clpsplug/how-do-you-debug-a-python-script-that-crashes-python-itself-4hpc</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;faulthandler.enable()&lt;/code&gt;; Python will print the stack trace to stderr before fully crashing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backstory
&lt;/h2&gt;

&lt;p&gt;Today I tried to daemonize a Python script that calls &lt;code&gt;request.get&lt;/code&gt; on macOS, and it was insta-dying for no apparent reason.&lt;br&gt;
I tested without daemonization, but the problem only popped up when I daemonize it.&lt;/p&gt;

&lt;p&gt;I was doing something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;daemon&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DaemonContext&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;daemon.pidfile&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PIDLockFile&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;


&lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PIDLockFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;home_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pidfile_watcher&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;fp&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;out.log&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fpe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;err.log&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;DaemonContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;pidfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fpe&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://example.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;fpe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Many researches, &lt;code&gt;print()&lt;/code&gt;s and one final check on Console.app (the macOS standard logger) later, I found that it was segfaulting at requests.get().&lt;/p&gt;
&lt;h2&gt;
  
  
  Why did it take so long?
&lt;/h2&gt;

&lt;p&gt;Because daemonized script don't properly log its death even when you pass a file pointer for stderr.&lt;br&gt;&lt;br&gt;
Also, crash report found in Console.app does not provide much information unless you write most of your program (note the word 'program' - this includes not only your script, but also Python packages and/or even Python itself)! So the only realistic bet may be to spam &lt;code&gt;print()&lt;/code&gt;, which is already tedious because you need to properly tell &lt;code&gt;DaemonContext&lt;/code&gt; to redirect stdout to a file (I didn't give any at first, which caused even more headaches).&lt;/p&gt;
&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;It was &lt;code&gt;faulthandler.enable()&lt;/code&gt; that I needed to call.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://docs.python.org/3/library/faulthandler.html" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdocs.python.org%2F3%2F_static%2Fog-image.png" height="200" class="m-0" width="200"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://docs.python.org/3/library/faulthandler.html" rel="noopener noreferrer" class="c-link"&gt;
          faulthandler — Dump the Python traceback — Python 3.13.0 documentation
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          This module contains functions to dump Python tracebacks explicitly, on a fault, after a timeout, or on a user signal. Call faulthandler.enable() to install fault handlers for the SIGSEGV, SIGFPE, ...
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdocs.python.org%2F3%2F_static%2Fpy.svg" width="16" height="16"&gt;
        docs.python.org
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;This causes Python to print stack trace to stderr when signal is received (in macOS, segmentation fault causes a signal SIGSEGV; probably all *nix systems also does.) instead of straight-up dying on the spot. This method enabled me to pinpoint exactly which call was causing my script to crash.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was the problem, by the way?
&lt;/h2&gt;

&lt;p&gt;Turns out, this is a &lt;a href="https://bugs.python.org/issue30385" rel="noopener noreferrer"&gt;known, (probably) unavoidable issue when using request package in macOS.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To avoid this issue, you must drop proxy support as &lt;a href="https://bugs.python.org/issue30385#msg293958" rel="noopener noreferrer"&gt;segfault occurs at process related to polling OS's proxy configuration, which is "not fork safe".&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;no_proxy&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>python</category>
    </item>
    <item>
      <title>Beware of 'padding' in TextMeshPro</title>
      <dc:creator>C. Plug</dc:creator>
      <pubDate>Mon, 06 Feb 2023 14:31:38 +0000</pubDate>
      <link>https://dev.to/clpsplug/beware-of-padding-in-textmeshpro-8ae</link>
      <guid>https://dev.to/clpsplug/beware-of-padding-in-textmeshpro-8ae</guid>
      <description>&lt;h2&gt;
  
  
  TextMeshPro renders text wrong?
&lt;/h2&gt;

&lt;p&gt;When you want to display text in Unity (starting circa version 2021,) the text components default to TextMeshPro (TMP).&lt;br&gt;
TextMeshPro makes you create an asset called "Font Asset" before you can display anything. It contains a Font Atlas, which is a collection of pre-rendered letters packed into a single image, whose mapping TMP keeps track of to display the text afterwards.&lt;br&gt;&lt;br&gt;
When making the atlas, you can set the &lt;strong&gt;sampling point size&lt;/strong&gt; (SPS), which is the font size used to pre-render the letters. This also translates to the biggest font size at which TMP can safely display the letters (for the most part). For example, smaller SPS sometimes characters to be positioned incorrectly. Bigger SPS requires larger atlas size, but it helps you avoid weird issues... or does it?&lt;/p&gt;

&lt;p&gt;Let's try an excessive case: we crank up the atlas size to maximum (8192 x 8192) and create the font atlas. With the auto sizing option for SPS, we should get a nicest result, right?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gyazo.com/d09b237d41dafa8e1f0766ee1f81c607" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fure4txwwgqmg37930a9p.png" alt="An English sentence displayed using an excessively large Font Atlas via TextMeshPro. The letters appear to be contained in semitransparent boxes." width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;... ⁉️&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Of course, I did not add any font-related effects or shader effects or something related to that. This is a TMP text displayed with the default setting with the Font Asset we just created.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Environment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Unity 2021.3.6f1&lt;/li&gt;
&lt;li&gt;TextMeshPro 3.0.6&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Let's see what happened
&lt;/h2&gt;

&lt;p&gt;For this experiment, we use M+ Font (2p) which can be retrieved from Google Fonts (or directly from M+ Font distribution site)&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://fonts.google.com/specimen/M+PLUS+2?query=m+plus" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.gstatic.com%2Fimages%2Ficons%2Fmaterial%2Fapps%2Ffonts%2F1x%2Fcatalog%2Fv5%2Fopengraph_color.png" height="420" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://fonts.google.com/specimen/M+PLUS+2?query=m+plus" rel="noopener noreferrer" class="c-link"&gt;
          M PLUS 2 - Google Fonts
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          M+ FONTS is a little nifty font family for everyday usage. Mplus 2 is a Sans Serif font with nine weights from Thin to Black, supporting 5,700+ Kanjis for Japan
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.gstatic.com%2Fimages%2Ficons%2Fmaterial%2Fapps%2Ffonts%2F1x%2Fcatalog%2Fv5%2Ffavicon.svg" width="16" height="16"&gt;
        fonts.google.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;We just created a Font Asset with the maximum possible atlas size. TMP's Font Asset Creator reports the atlas information, so let's take a look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gyazo.com/5685a6f53ebc7d0671ff2c0213b6ee88" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2mox2izebwgy7d35p24i.png" alt="Log for big font atlas" width="800" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"Point Size" is the SPS that TMP has chosen for this atlas generation. It reports it's &lt;strong&gt;1394&lt;/strong&gt;. Quite excessive, but let's move on for now.&lt;/p&gt;

&lt;p&gt;For comparison, let's also create a Font Asset with a sensibly-sized atlas:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gyazo.com/640a3c5c357369f315cab34b20a38c56" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fidkj7ln87dr2qwfu80l1.png" alt="Log for small font atlas" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The SPS this time is just &lt;strong&gt;23&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now what happens if we display text using those fonts?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gyazo.com/5e494ea076148bc9c5f5ddb064151cdf" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg3wsl4amt5cedmwf9633.png" alt="In this image, we compare 2 Text Mesh Pro labels displaying some texts. One label uses the font asset with an excessively large atlas while other uses the asset with a sensibly-sized atlas. To our surprise, the label using the excessively large font asset is rendering the text wrong; each letter is surrounded by a transparent box." width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The label using the big font asset has catastrophically failed to render the text correctly!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;This issue has been raised in &lt;a href="https://forum.unity.com/threads/text-mesh-pro-box-around-text-unwanted-effect-bug.665647/" rel="noopener noreferrer"&gt;Unity Forum&lt;/a&gt;; the SPS becomes larger as the atlas size gets bigger... and it becomes too big for the character to be way too tightly packed! Each character needs to be spaced out for TMP to work correctly.&lt;br&gt;
To space them out, you need to use, you guessed it, the Spacing property.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forum.unity.com/threads/text-mesh-pro-box-around-text-unwanted-effect-bug.665647/" rel="noopener noreferrer"&gt;https://forum.unity.com/threads/text-mesh-pro-box-around-text-unwanted-effect-bug.665647/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
(This link appears to redirect too many times here and I cannot seem to embed it. WAT?)&lt;/p&gt;

&lt;p&gt;In the thread, the Sampling Point Size and Padding should satisfy the next formula:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;SPSPadding=10
\frac{\text{SPS}}{\text{Padding}} = 10 
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mopen nulldelimiter"&gt;&lt;/span&gt;&lt;span class="mfrac"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Padding&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="frac-line"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;SPS&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose nulldelimiter"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;10&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;p&gt;If you look at the log closely, this ratio is reported &lt;code&gt;SP/PD Ratio&lt;/code&gt;. The value here should say &lt;code&gt;10%&lt;/code&gt; or somewhere around that value.&lt;/p&gt;

&lt;p&gt;SPS defaults to &lt;code&gt;Auto Sizing&lt;/code&gt; when you first introduce TMP to your project. This means that TMP will adjust the SPS according to the Font Atlas size. However, there is no way (and no apparent instructions) to set the Padding automatically (it defaults to 5 and can be as big as 64), so it may fly under your radar.&lt;/p&gt;

&lt;p&gt;If you only need ASCII, the size of 512x512 ~ 1024x1024 should do. If you choose to set your SPS yourself, you can control it further and you don't even need to force the atlas to be a square. Just make sure that SPS/PD ratio is 10%, and find the atlas size that can pack the letters as tightly as possible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gyazo.com/baad5747added05a5fc9dd6a0ea707e1" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fznbs1cxkvsdindg9sy76.png" alt="Setting SPS yourself. Notice that SPS/PD ratio is 10%." width="800" height="530"&gt;&lt;/a&gt;&lt;br&gt;
(Setting SPS yourself. Notice that SPS/PD ratio is 10%.)&lt;/p&gt;

</description>
      <category>unity3d</category>
    </item>
    <item>
      <title>How the Unity's new Input System liberates the input detection from frame-rate</title>
      <dc:creator>C. Plug</dc:creator>
      <pubDate>Sun, 22 Jan 2023 03:53:47 +0000</pubDate>
      <link>https://dev.to/clpsplug/how-the-unitys-new-input-system-liberates-the-input-detection-from-frame-rate-17k6</link>
      <guid>https://dev.to/clpsplug/how-the-unitys-new-input-system-liberates-the-input-detection-from-frame-rate-17k6</guid>
      <description>&lt;p&gt;Unity's conventional input system is easy to use, but there is one issue with it - it is frame locked.&lt;/p&gt;

&lt;p&gt;Not sure what that means? Let me show you: if you are new to Unity, chances are that you have read or even written this piece of code yourselves.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Sample&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetKeyDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KeyCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Space&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Space pressed now"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This code has one major restriction - &lt;strong&gt;it can detect key presses&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;only when the &lt;code&gt;Update()&lt;/code&gt; is called.&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;Update()&lt;/code&gt; is called every frame, so as you may usually enable VSync and/or with everything going on with your actual game, you would be only checking if the key is pressed around 60 times per a second.&lt;br&gt;&lt;br&gt;
This is actually fine for most of the use cases - after all, it may be sufficient for you to check the key input every frame and there will be no disadvantages to the player.&lt;/p&gt;

&lt;p&gt;But what if there was one?&lt;/p&gt;

&lt;p&gt;There actually are several use cases.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to detect the mouse movement as a part of the player's action set, but any frame rate drop makes the movement jaggy, which you don't want.&lt;/li&gt;
&lt;li&gt;The precise timing of the input is required to the point that you want to know &lt;em&gt;when within the interval between the frames the key was pressed.&lt;/em&gt; (e.g., music games should be doing this or must find a workaround such that the judgment is bound to the frames.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's possible &lt;strong&gt;with the new input system!&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Introduce &lt;code&gt;InputActionTrace&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;(Disclaimer: I'm skipping how we migrate to the conventional Input System to the new one - look it up)&lt;/p&gt;

&lt;p&gt;With the new Input System, we have a powerful class called &lt;code&gt;InputActionTrace&lt;/code&gt; in our arsenal. You will be using this class as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create &lt;code&gt;InputActionTrace&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.SubscribeTo()&lt;/code&gt; the &lt;code&gt;InputAction&lt;/code&gt; you want to check the input outside the confine of the frame rate&lt;/li&gt;
&lt;li&gt;Directly &lt;code&gt;foreach&lt;/code&gt; on the &lt;code&gt;InputActionTrace&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.Clear()&lt;/code&gt; the trace&lt;/li&gt;
&lt;li&gt;When done, &lt;code&gt;.UnsubscribeFromAll()&lt;/code&gt; and &lt;code&gt;.Dispose()&lt;/code&gt; of the trace.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.InputSystem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.InputSystem.Utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Sample&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;InputActionAsset&lt;/span&gt; &lt;span class="n"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;InputActionTrace&lt;/span&gt; &lt;span class="n"&gt;_trace&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_trace&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InputActionTrace&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;_trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SubscribeTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindActionMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Default"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;FindAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Important - required to open up the potential of your input devices,&lt;/span&gt;
    &lt;span class="c1"&gt;// But keep in mind that NOT ALL DEVICES ARE COMPATIBLE.&lt;/span&gt;
    &lt;span class="n"&gt;InputSystem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pollingFrequency&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_trace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadValue&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// This is where you do stuff&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UnsubscribeFromAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;_trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For each frame, your &lt;code&gt;_trace&lt;/code&gt; will contain everything occurred from the last frame to the current one; and it contains useful information!&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;.ReadValue&amp;lt;T&amp;gt;()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The value returned from the iterator can be used just like the regular &lt;code&gt;InputAction&lt;/code&gt; object, for the most part. So you can &lt;code&gt;ReadValue&amp;lt;T&amp;gt;()&lt;/code&gt; off of it like nothing has changed:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_trace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadValue&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;...except that now you have every event happened from the last frame!&lt;br&gt;&lt;br&gt;
If you are drawing a line, then this will help you draw a smooth line even if your game runs at 5fps or something!&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;.time&lt;/code&gt; property
&lt;/h3&gt;

&lt;p&gt;This is the great property to make use of - this is &lt;strong&gt;the timestamp of the action occurred!&lt;/strong&gt; Combined with &lt;code&gt;Time.realtimeSinceStartupAsDouble&lt;/code&gt; (as it shares the epoch with this property,) &lt;strong&gt;you can tell how many seconds before the frame the action occurred!&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_trace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;realTimeSinceStartUpAsDouble&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"This action has occurred &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; seconds before this frame."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Sample
&lt;/h2&gt;

&lt;p&gt;I have been making an input manager for my games, and with this example, I show the concept of using the &lt;code&gt;.time&lt;/code&gt; property to retrieve the timestamp for the action precisely - take a look!&lt;br&gt;
(I implement the input detection from the code side as much as possible, so there's stuff that is a bit off from many tutorials out there.)&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Clpsplug" rel="noopener noreferrer"&gt;
        Clpsplug
      &lt;/a&gt; / &lt;a href="https://github.com/Clpsplug/InputManager" rel="noopener noreferrer"&gt;
        InputManager
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Wrapper to handle Unity's new Input System's triggers from code. NOTE: It is not production ready yet.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Input Manager&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;WARNING!&lt;/strong&gt;: This plugin is not stable yet!!&lt;/p&gt;

&lt;p&gt;This plugin for Unity3D is the wrapper for using Unity's New Input Manager
programatically (i.e., without using related components.)&lt;br&gt;
With this plugin, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Handle key presses as your custom &lt;code&gt;enums&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Handle key presses in a 'frame-unlocked' manner&lt;/li&gt;
&lt;li&gt;"Hold frame count" with small effect from framerate fluctuation&lt;/li&gt;
&lt;li&gt;Rebinding the assigned key (i.e., key config.)
&lt;ul&gt;
&lt;li&gt;Output the custom bindings as serializable dictionary format&lt;/li&gt;
&lt;li&gt;"Duplicate keys" detection; if rebind causes one key bound to two actions, the plugin will try to swap the binds between them instead&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;How to use?&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Please see the &lt;a href="https://github.com/Clpsplug/InputManagerPackages/com.clpsplug.input-manager/README.md" rel="noopener noreferrer"&gt;README inside the package&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Acknowledgements&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;The sample project includes a TextMeshPro-rendered version of &lt;a href="https://github.com/coz-m/MPLUS_FONTS" rel="noopener noreferrer"&gt;M+ Font&lt;/a&gt;,
which is avaiable under &lt;a href="https://github.com/coz-m/MPLUS_FONTS/blob/master/OFL.txt" rel="noopener noreferrer"&gt;SIL Open Font License 1.1&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Clpsplug/InputManager" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;In the &lt;code&gt;FrameUnlockedSampleScene&lt;/code&gt; I prepared several labels that displays the data for the action - press the Space key to check the output, and also toggle VSync in the &lt;code&gt;Game&lt;/code&gt; window.&lt;/p&gt;

&lt;h3&gt;
  
  
  Without VSync
&lt;/h3&gt;

&lt;p&gt;Note the FPS - it's over 1000 so we won't be seeing values bigger than like 10ms difference for the most part.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gyazo.com/3c43af85edabbaa0c8c890b6f4330b24" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fky4l0v6gem3gtqt8c8f5.gif" alt="Image from Gyazo" width="760" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  With VSync
&lt;/h3&gt;

&lt;p&gt;Now we're confined to 60fps - we should be seeing values around 16ms at most, which we do!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gyazo.com/9f727100c29273200e9003d440e31fbc" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqximr1u86d7tmixg0nc7.gif" alt="Image from Gyazo" width="720" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;p&gt;It seems there is a small GC allocation at the &lt;code&gt;foreach&lt;/code&gt; section - it is small, but you should know that GC will occur periodically. The trace can still pick up the input actions missed during the dropped frames, so it shouldn't be too much of a problem, though.&lt;/p&gt;

&lt;p&gt;Another point to make is that although this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="n"&gt;InputSystem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pollingFrequency&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;causes the polling frequency to be 1000Hz, &lt;strong&gt;not all devices are compatible with this settings.&lt;/strong&gt; Devices that are "polled" will be affected by this line. Although I don't have Windows PC to test, I heard that mice on Windows are most likely compatible with this. Keyboards may also be. If you set this to high number and you still don't get as much events as you hoped, then the device in question may not be getting polled (and instead, inputs are received from OS's API or something.)&lt;br&gt;&lt;br&gt;
It's still a good idea, though, because unexpected frame loss (= Update() failing to fire) can happen. In the example below, I'm playing my own music game, but I set &lt;code&gt;Application.targetFrameRate = 5;&lt;/code&gt;. Notice that though this is a game that requires strict timing, I can keep getting "Perfect"s.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1608748818211930112-367" src="https://platform.twitter.com/embed/Tweet.html?id=1608748818211930112"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1608748818211930112-367');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1608748818211930112&amp;amp;theme=dark"
  }



&lt;/p&gt;

</description>
      <category>unity3d</category>
    </item>
    <item>
      <title>Typeset LaTeX files with TeX Live on macOS and IntelliJ IDEA</title>
      <dc:creator>C. Plug</dc:creator>
      <pubDate>Wed, 16 Nov 2022 01:00:00 +0000</pubDate>
      <link>https://dev.to/clpsplug/typeset-latex-files-with-tex-live-on-macos-and-intellij-idea-25o7</link>
      <guid>https://dev.to/clpsplug/typeset-latex-files-with-tex-live-on-macos-and-intellij-idea-25o7</guid>
      <description>&lt;h2&gt;
  
  
  So you want to typeset LaTeX locally
&lt;/h2&gt;

&lt;p&gt;Nowadays, we have the luxury of 'cloud LaTeX services' like &lt;a href="https://www.overleaf.com" rel="noopener noreferrer"&gt;Overleaf&lt;/a&gt;, but sometimes you will run into timeout issues because you used a bit too many images.&lt;br&gt;&lt;br&gt;
It will never be a problem if you can just typeset LaTeX locally,&lt;br&gt;
so here's the setup I use for my purposes.&lt;br&gt;&lt;br&gt;
Note that I need a &lt;strong&gt;CJK environment&lt;/strong&gt;, or more specifically,&lt;br&gt;
I need to be able to typeset Japanese characters.&lt;/p&gt;
&lt;h2&gt;
  
  
  Environment
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;macOS Monterey 12.6 (21G115)
TeX Live 2022
IntelliJ IDEA 2022.2.3 (Ultimate Edition (Student License should work as well, haven't tested Community))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Get MacTeX
&lt;/h2&gt;

&lt;p&gt;On macOS, you want to use MacTeX to get TeX Live.&lt;br&gt;
There are many ways you can get MacTeX,&lt;br&gt;
but I used homebrew: &lt;code&gt;brew install --cask mactex&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Add TeX support to IntelliJ IDEA
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://www.jetbrains.com/idea/" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fresources.jetbrains.com%2Fstorage%2Fproducts%2Fintellij-idea%2Fimg%2Fmeta%2Fpreview.png" height="450" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://www.jetbrains.com/idea/" rel="noopener noreferrer" class="c-link"&gt;
          IntelliJ IDEA – the Leading Java and Kotlin IDE
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          IntelliJ IDEA is undoubtedly the top-choice IDE for software developers. It makes Java and Kotlin development a more productive and enjoyable experience.

        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.jetbrains.com%2Ffavicon.ico%3Fr%3D1234" width="800" height="400"&gt;
        jetbrains.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Yes, IntelliJ IDEA is originally for Java. But if you use Ultimate Edition, then you can use PHP, Ruby and Go, etc.&lt;br&gt;
There are more languages (both programming and markup) it can support by installing plugins!&lt;/p&gt;

&lt;p&gt;For LaTeX, you will use this:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://plugins.jetbrains.com/plugin/9473-texify-idea" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fplugins.jetbrains.com%2Ffiles%2F9473%2F617381%2Ficon%2FpluginIcon.png" height="600" class="m-0" width="600"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://plugins.jetbrains.com/plugin/9473-texify-idea" rel="noopener noreferrer" class="c-link"&gt;
          TeXiFy IDEA - IntelliJ IDEs Plugin | Marketplace
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fresources.jetbrains.com%2Fstorage%2Fui%2Ffavicons%2Ffavicon.ico" width="800" height="400"&gt;
        plugins.jetbrains.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This plugin enables not only syntax highlighting, but also TeX command completion&lt;br&gt;
and &lt;strong&gt;Run Configuration template for LaTeX!&lt;/strong&gt;&lt;br&gt;
We will use this template to typeset our LaTeX on IDEA.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up Run Configuration
&lt;/h2&gt;

&lt;p&gt;This is where I stumbled &lt;strong&gt;a lot.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When typesetting Japanese, &lt;code&gt;latexmk&lt;/code&gt;, which is a tool that chain-calls typesetting commands, is the tool to go.&lt;/p&gt;

&lt;p&gt;We need to create a config file called &lt;code&gt;latexmkrc&lt;/code&gt;.&lt;br&gt;
This can exist either in your home dir or in the project root&lt;br&gt;
with the filename &lt;code&gt;.latexmkrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Most sources I searched suggests the following content as our &lt;code&gt;latexmkrc&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env perl&lt;/span&gt;
&lt;span class="nv"&gt;$pdf_mode&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$latex&lt;/span&gt;            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;platex -halt-on-error&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;$latex_silent&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;platex -halt-on-error -interaction=batchmode&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;$bibtex&lt;/span&gt;           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pbibtex&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;$dvipdf&lt;/span&gt;           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dvipdfmx %O -o %D %S&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;$makeindex&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mendex %O -o %D %S&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have the stuff, we look at the Run Configuration.&lt;/p&gt;

&lt;p&gt;If the plugin is installed correctly, you should be able to find the &lt;code&gt;LaTeX&lt;/code&gt; template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gyazo.com/c8643c05703fa596985197c3856606bd" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fho3668wwz9bab5xqtjl5.png" alt="Image from Gyazo" width="678" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this is where stuff gets complicated:&lt;br&gt;
&lt;strong&gt;Because of macOS's security measure, commands installed at specific paths requires user's explicit path specification.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;And &lt;code&gt;latexmk&lt;/code&gt; is installed at such a path.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For this reason, simply setting &lt;code&gt;Compiler&lt;/code&gt; to &lt;code&gt;Latexmk&lt;/code&gt; is not enough.&lt;br&gt;&lt;br&gt;
(...which is the very reason I suffered. I spent like an hour to learn this the hard way)&lt;/p&gt;

&lt;p&gt;Usually, &lt;code&gt;latexmk&lt;/code&gt; exists here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/Library/TeX/texbin/latexmk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...or you can use &lt;code&gt;which&lt;/code&gt; command and &lt;code&gt;pbcopy&lt;/code&gt; the result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;which latexmk | pbcopy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;if you didn't know, pbcopy is a macOS original command which copies output of command to clipboard!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now you need to enable &lt;code&gt;Select custom compiler executable path (required on Mac OS X)&lt;/code&gt; and paste the path!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gyazo.com/7e27d6dd520f13d49771586f90901bfd" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F97u7oos4h5g44bvnh5ib.png" alt="Image from Gyazo" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[BY THE WAY]&lt;br&gt;&lt;br&gt;
PDF Viewer: With the plugin &lt;code&gt;PDF Viewer&lt;/code&gt;, you should be able to select &lt;code&gt;Built-in PDF Viewer&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
Note, however, that this PDF viewer may fail to render Japanese characters&lt;br&gt;
when the PDF file itself contain Japanese character.&lt;br&gt;&lt;br&gt;
To be &lt;em&gt;absolutely&lt;/em&gt; sure, you may want to use macOS's Preview.app.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Scroll down a bit and you will find the following:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Main file to compile&lt;/td&gt;
&lt;td&gt;This &lt;strong&gt;must&lt;/strong&gt; be a full-path! (For some reason.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Directory for output files&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;{projectDir}/output&lt;/code&gt; causes the output to go to &lt;code&gt;output&lt;/code&gt; directory under the project root.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output format&lt;/td&gt;
&lt;td&gt;DEFAULT&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;...are the values to set.&lt;br&gt;
I recommend that &lt;code&gt;Directory for output files&lt;/code&gt; be set to &lt;code&gt;{projectDir}/output&lt;/code&gt;&lt;br&gt;
because LaTeX outputs all sort of files besides PDF (like 10 of them!!)&lt;br&gt;&lt;br&gt;
You probably don't want your project dir to be cluttered just because you've typeset your LaTeX file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gyazo.com/f6ee0759d579fb3c2809814071fe770d" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0djlv1eippyuk1nozixa.png" alt="Image from Gyazo" width="800" height="834"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give an appropriate name to &lt;code&gt;Name:&lt;/code&gt;, save by clicking [OK], &lt;br&gt;
And &lt;code&gt;Run&lt;/code&gt; (green arrow at the top of the window) to compile the file!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gyazo.com/2fcfb951f40ff04ca23ed78cdf847353" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mmvrkdnhfphvigtuf5r.png" alt="Image from Gyazo" width="432" height="78"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By the way, you can find these settings within the red rectangle at &lt;code&gt;Languages &amp;amp; Frameworks &amp;gt; TeXiFy&lt;/code&gt;&lt;br&gt;
in the IDEA preferences.&lt;br&gt;
Checking both of these will initiate compilation every time you save your LaTeX files.&lt;br&gt;
Maybe worth trying if your PC can handle it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gyazo.com/b9f004b6b939f68e0c9ad4a376aff414" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fheoy0kduk09ntga2pu8z.png" alt="Image from Gyazo" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>latex</category>
      <category>intellij</category>
      <category>macos</category>
    </item>
    <item>
      <title>Creating Custom Tags in Jekyll, with an actual example</title>
      <dc:creator>C. Plug</dc:creator>
      <pubDate>Tue, 19 Jul 2022 03:58:45 +0000</pubDate>
      <link>https://dev.to/clpsplug/creating-custom-tags-in-jekyll-with-an-actual-example-1dp3</link>
      <guid>https://dev.to/clpsplug/creating-custom-tags-in-jekyll-with-an-actual-example-1dp3</guid>
      <description>&lt;p&gt;Shields.io is a "service for concise, consistent, and legible badges in SVG and raster format, which can easily be included in GitHub readmes or any other web page."&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://shields.io/" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshields.io%2Fimg%2Flogo.png" height="auto" class="m-0"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://shields.io/" rel="noopener noreferrer" class="c-link"&gt;
          Shields.io | Shields.io
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Concise, consistent, and legible badges
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshields.io%2Fimg%2Ffavicon.ico"&gt;
        shields.io
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Their service takes query parameters to their API endpoint to generate a badge / shield. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://img.shields.io/static/v1?label=Find%20me%20on&amp;amp;message=GitHub&amp;amp;color=181717&amp;amp;style=flat&amp;amp;logo=github
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;becomes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fstatic%2Fv1%3Flabel%3DFind%2520me%2520on%26message%3DGitHub%26color%3D181717%26style%3Dflat%26logo%3Dgithub" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fstatic%2Fv1%3Flabel%3DFind%2520me%2520on%26message%3DGitHub%26color%3D181717%26style%3Dflat%26logo%3Dgithub" alt="My GitHub"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was planning to use this in my personal blog, when I realized a problem; it is hard to maintain.&lt;br&gt;
While it may be rare to change the content of those shields, it would be nice to have a maintainable way to put a shield on my blog.&lt;/p&gt;

&lt;p&gt;Since I use Jekyll, I can define a custom 'Liquid tag.' Just like we can embed stuff from compatible services with liquid tags here in DEV.to, e.g.,  &lt;code&gt;{% github repo %}&lt;/code&gt; and &lt;code&gt;{% embed website %}&lt;/code&gt;, we can make a custom tag, say, &lt;code&gt;{% shields_io payload %}&lt;/code&gt;, to display a shield.&lt;/p&gt;
&lt;h2&gt;
  
  
  How does Liquid tag on Jekyll work?
&lt;/h2&gt;

&lt;p&gt;The Liquid tag on Jekyll takes the following format:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight liquid"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tag_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;tag_argument&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It has a tag name, and one optional argument.&lt;/p&gt;

&lt;p&gt;See the problem here? There is at most one value accepted as an argument. Shields.io takes way more than that, and putting query parameter here does not solve anything.&lt;/p&gt;

&lt;p&gt;There is still hope, though; let's take a look at the code we'll be writing.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Jekyll&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomTag&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Liquid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Tag&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tag_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parse_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;super&lt;/span&gt;
      &lt;span class="c1"&gt;# @type [String]&lt;/span&gt;
      &lt;span class="vi"&gt;@arg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="s2"&gt;"The argument is &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@arg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;# return the render result here&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;arg&lt;/code&gt; argument is the argument passed from the tag. It's a string. So we can do something with the input.&lt;br&gt;&lt;br&gt;
And looking back at the original problem, we are trying to pass a set of key-value pairs to an API endpoint.&lt;/p&gt;

&lt;p&gt;So, I decided to pass a JSON payload here; it can be prettified for our purposes, and Ruby supports JSON deserialization out of the box.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to turn it into the URL
&lt;/h2&gt;

&lt;p&gt;Since Ruby can turn the input JSON into a hash, we can iterate on this hash and construct the query parameter.&lt;/p&gt;

&lt;p&gt;So the idea is to deserialize the JSON and store it in a variable:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tag_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parse_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;super&lt;/span&gt;
      &lt;span class="c1"&gt;# @type [Hash]&lt;/span&gt;
      &lt;span class="vi"&gt;@config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And construct the query parameter. I also decided to include &lt;code&gt;href&lt;/code&gt; and &lt;code&gt;alt&lt;/code&gt; for other purposes into the JSON payload, but they are not relevant for the request. So I extract their values and remove it from the input hash before turning the rest into the query parameter.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;alt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:alt&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="vi"&gt;@config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:alt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;shield_tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;&lt;span class="sh"&gt;
  &amp;lt;img src="https://img.shields.io/static/v1?&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;hash_to_query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"
&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;alt&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
    &lt;span class="n"&gt;shield_tag&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;" alt=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;alt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; /&amp;gt;"&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;shield_tag&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;" /&amp;gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;&lt;span class="sh"&gt;
&amp;lt;a href="&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&amp;gt;
&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shield_tag&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
&amp;lt;/a&amp;gt;
&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;shield_tag&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="kp"&gt;private&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hash_to_query&lt;/span&gt;
  &lt;span class="vi"&gt;@config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt; &lt;span class="s1"&gt;'&amp;amp;'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;p&gt;Here is my creation - copy the last two files and run a local server!&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



</description>
      <category>ruby</category>
      <category>jekyll</category>
    </item>
    <item>
      <title>How to include secondary Jekyll website using submodule</title>
      <dc:creator>C. Plug</dc:creator>
      <pubDate>Tue, 05 Jul 2022 08:55:52 +0000</pubDate>
      <link>https://dev.to/clpsplug/how-to-include-secondary-jekyll-website-using-submodule-41co</link>
      <guid>https://dev.to/clpsplug/how-to-include-secondary-jekyll-website-using-submodule-41co</guid>
      <description>&lt;h2&gt;
  
  
  Caveat
&lt;/h2&gt;

&lt;p&gt;The technique explained in this article expects that you own an HTTP server that you can run ruby/bundler on and build your Jekyll site on.&lt;br&gt;
&lt;em&gt;This technique is not available for GitHub Pages.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;After several month of Jekylling, I found it tedious to build my site locally and to upload it with &lt;code&gt;scp&lt;/code&gt;, &lt;code&gt;rsync&lt;/code&gt;, or something. I wanted my site to be built on the server, so that's what I did.&lt;br&gt;
Then I realized I had another website which was hosting a blog at the "root directory" of your website while serving another Jekyll site at the different directly inside that.&lt;br&gt;&lt;br&gt;
Specifically, I had my dev blog and it also had product pages in the subdirectory and that page took advantage of &lt;code&gt;_data&lt;/code&gt; directory and so on. It would be less confusing if you could source-control the two blogs separately by isolating them into different repositories.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example.com/  # A Jekyll site (A)
|- /2022/06/20  # Root level blog for site (A)
|- /another_product  # Separate Jekyll site (B)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I have tinkered around the Jekyll configuration and managed to pull it off, which I'll share with you here.&lt;/p&gt;
&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create a source directory in your root blog project and move source there. Remember the dir name, you will use that later&lt;/li&gt;
&lt;li&gt;Include your &lt;em&gt;secondary site&lt;/em&gt; as a submodule at the project root&lt;/li&gt;
&lt;li&gt;Edit your &lt;strong&gt;root site _config.yml&lt;/strong&gt; to exclude that submodule from root site build procedure
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# The source directory you have created.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Build &lt;em&gt;the submodule site&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;cd &lt;/span&gt;submodule_site
  &lt;span class="nv"&gt;JEKYLL_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production bundle &lt;span class="nb"&gt;exec &lt;/span&gt;jekyll build
  &lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;In the &lt;strong&gt;output directory of your root Jekyll site,&lt;/strong&gt; create a symlink (e.g., submodule_site) pointing to &lt;em&gt;the output directory of secondary Jekyll site&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT_ROOT&lt;/span&gt;/_site
  &lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; ../submodule_site/_site submodule_site  &lt;span class="c"&gt;# This will be a part of your actual link!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Edit your &lt;strong&gt;root site _config.yml&lt;/strong&gt; to include this line
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;keep_files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;submodule_site"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Build both sites&lt;/li&gt;
&lt;li&gt;Profit&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  First thing first
&lt;/h2&gt;

&lt;p&gt;When you do something like this, you should consider moving your website source into a directory of your choice, as including another Jekyll website as a submodule may confuse Jekyll.&lt;br&gt;
This is because, by default, most of the stuff in the project root is considered the source for the blog. Having another Jekyll project in such place can mangle everything.&lt;br&gt;
Consult my another post on how to do this:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/clpsplug" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F43590%2F9796aed2-75e3-499d-b898-319d3c633737.jpeg" alt="clpsplug"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/clpsplug/use-source-jekyll-configuration-to-avoid-deployment-mistake-gec" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Use "source" Jekyll configuration to avoid deployment mistake&lt;/h2&gt;
      &lt;h3&gt;C. Plug ・ May 22 '22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#jekyll&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#ruby&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Jekyll wants to play clean
&lt;/h2&gt;

&lt;p&gt;If you put a symlink to the output directory of your submodule site into your source directory (by default it is your project root,) everything &lt;em&gt;blows up&lt;/em&gt; at build time for some reason.&lt;/p&gt;

&lt;p&gt;Now, the only thing we could possibly do is to create a symlink to the output dir of the submodule site into the output dir of the root site.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;root_site/_site
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; ../submodule_site/_site submodule_site
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But this does not work as &lt;strong&gt;everything in &lt;code&gt;_site&lt;/code&gt; directory is wiped clean every build.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is, however, a configuration key to stop this behavior.&lt;/p&gt;
&lt;h2&gt;
  
  
  The &lt;code&gt;keep_files&lt;/code&gt; key
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://jekyllrb.com/docs/configuration/options/" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjekyllrb.com%2Fimg%2Fjekyll-og.png" height="auto" class="m-0"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://jekyllrb.com/docs/configuration/options/" rel="noopener noreferrer" class="c-link"&gt;
          Configuration Options | Jekyll • Simple, blog-aware, static sites
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          The tables below list the available settings for Jekyll, and the various options (specified in the configuration file) and flags (specified on the command-line) that control them.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjekyllrb.com%2Ffavicon.ico"&gt;
        jekyllrb.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;You can use &lt;code&gt;keep_files&lt;/code&gt; key to tell Jekyll to leave specific files/directories behind before performing a clean on build. This key works for symlinks, too!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;keep_files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;submodule_site"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Time to build
&lt;/h2&gt;

&lt;p&gt;By building both the submodule site and the root site, you will have created a working site in the &lt;code&gt;_site&lt;/code&gt; directory. By symlinking the output dir of the root site to your webroot, you can serve the website!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>jekyll</category>
      <category>git</category>
      <category>submodule</category>
    </item>
    <item>
      <title>Use "source" Jekyll configuration to avoid deployment mistake</title>
      <dc:creator>C. Plug</dc:creator>
      <pubDate>Sun, 22 May 2022 12:40:14 +0000</pubDate>
      <link>https://dev.to/clpsplug/use-source-jekyll-configuration-to-avoid-deployment-mistake-gec</link>
      <guid>https://dev.to/clpsplug/use-source-jekyll-configuration-to-avoid-deployment-mistake-gec</guid>
      <description>&lt;p&gt;By default, Jekyll includes into the website whatever exists at the project root minus some files and directories that has special meanings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my_jekyll_site
|- GemFile  // safe by default
|- GemFile.lock  // safe by default
|- _config.yml  // safe by default
|- .gitignore  // safe by default
|- index.md  // included
|- _posts  // included (parsed and then included)
 |- ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is one problem with this setup. &lt;strong&gt;If you add a script file here, you are going to expose that file!&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my_jekyll_site
|- Gemfile
|- ...
|- script.sh  // uh oh, you're exposing this file!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;There can be multiple reasons for creating a non-Jekyll related scripts, examples being:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automated build script for the server to publish your site&lt;/li&gt;
&lt;li&gt;Yarn/Webpack config for your javascript needs&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;You could specify &lt;code&gt;exclude&lt;/code&gt; key in your &lt;code&gt;_config.yml&lt;/code&gt;, but this is merely &lt;em&gt;a manual denylist&lt;/em&gt; - you may forget to add stuff until it is too late.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;webpack.js"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is even better way:&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;source&lt;/code&gt; key
&lt;/h2&gt;

&lt;p&gt;This tells Jekyll to stop looking at the project root for the content to build; instead, &lt;strong&gt;it will use the directory you have specified.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_src"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, you put everything into &lt;code&gt;_src&lt;/code&gt; directory and everything will work just as fine. No more need to update your &lt;code&gt;exclude&lt;/code&gt; key!&lt;/p&gt;

&lt;p&gt;One small notice is if you're generating stuff outside of Jekyll, e.g., transpiling your typescript, you need to point the input and output into the &lt;code&gt;source&lt;/code&gt; directory.&lt;/p&gt;

</description>
      <category>jekyll</category>
      <category>ruby</category>
    </item>
    <item>
      <title>I became tired of making manual deployment mistakes and this happened</title>
      <dc:creator>C. Plug</dc:creator>
      <pubDate>Sat, 14 May 2022 15:58:24 +0000</pubDate>
      <link>https://dev.to/clpsplug/i-became-tired-of-making-manual-deployment-mistakes-and-this-happened-5gl9</link>
      <guid>https://dev.to/clpsplug/i-became-tired-of-making-manual-deployment-mistakes-and-this-happened-5gl9</guid>
      <description>&lt;p&gt;This is the story of how I decided to automate the download process of Unity Cloud Build artifacts.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Clpsplug" rel="noopener noreferrer"&gt;
        Clpsplug
      &lt;/a&gt; / &lt;a href="https://github.com/Clpsplug/ucb-webhook-receiver" rel="noopener noreferrer"&gt;
        ucb-webhook-receiver
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Standalone Unity Cloud Build webhook receiver
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Unity Cloud Build Webhook Handler&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Powered by CherryPy&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is this?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This scripts boots a server that can accept webhook payloads from Unity Cloud Build
and handle the artifact so that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the latest artifacts are always at the specific paths&lt;/li&gt;
&lt;li&gt;the previous artifacts are archived with the timestamp at when the archive occurs.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This program was made to ensure that we don't have to download the artifacts from UCB by hand
and the correct artifacts are in the correct directories,
so that the same script can be used each time you update your game.&lt;/p&gt;
&lt;p&gt;This may be achievable with Jenkins, but I just simply wanted to write this for personal
educational purposes. So... whatevs.&lt;/p&gt;
&lt;p&gt;This script is made with SteamCMD in mind, but if you are downloading the artifacts
from Unity Cloud Build for uploading them to distributor using the similar tools,
this script is for you.&lt;/p&gt;
&lt;p&gt;Downloading them…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Clpsplug/ucb-webhook-receiver" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  A rather big set of binaries
&lt;/h2&gt;

&lt;p&gt;Let me set the scene for you.&lt;/p&gt;

&lt;p&gt;I have a game published on Steam - &lt;a href="https://store.steampowered.com/app/1352730/" rel="noopener noreferrer"&gt;Twin Horizons&lt;/a&gt;. It's a music game, and it's made with Unity.&lt;/p&gt;

&lt;p&gt;The repository I save the code employs the &lt;a href="https://danielkummer.github.io/git-flow-cheatsheet/index.html" rel="noopener noreferrer"&gt;git-flow&lt;/a&gt; model, and whenever there is a commit on the &lt;code&gt;base&lt;/code&gt; branch, it kicks builds on the Unity Cloud Build (thank &lt;em&gt;goodness&lt;/em&gt; they &lt;em&gt;finally&lt;/em&gt; supported IL2CPP for Windows.)  &lt;/p&gt;

&lt;p&gt;There are four targets, or types of the game executable, to be built. They are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;macOS version, Production Build&lt;/li&gt;
&lt;li&gt;macOS version, Developer Build w/ development tools&lt;/li&gt;
&lt;li&gt;Windows version, Production Build&lt;/li&gt;
&lt;li&gt;Windows version, Developer Build w/ development tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After they are built, I have to: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;download them &lt;/li&gt;
&lt;li&gt;place them on the specific location on my filesystem and&lt;/li&gt;
&lt;li&gt;add an Addressable bundle to all of them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is what I need to do so that the tools provided by Steam can see the new build.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Several month ago, I received a message from one of my tester that his installation broke on the latest update. &lt;em&gt;Ah s#!+, here we go again.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I gathered the logs. I tested on Unity. I even tested the built app. No luck. Heck, it was not even supposed to occur with the build he received.&lt;/p&gt;

&lt;p&gt;...or so I thought.&lt;/p&gt;

&lt;p&gt;Turns out, when I placed the executables, &lt;strong&gt;I made a mistake and placed the production version in the development version directory.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0f6eocngd6wkhpa6dtd2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0f6eocngd6wkhpa6dtd2.jpg" alt="FACEPALM" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Alex E. Proimos, &lt;a href="https://creativecommons.org/licenses/by/2.0" rel="noopener noreferrer"&gt;CC BY 2.0&lt;/a&gt;, via Wikimedia Commons&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thank &lt;em&gt;goodness&lt;/em&gt; it was not the other way around.&lt;/p&gt;

&lt;p&gt;...Come to think of it, I had a similar mess-ups in the past. I &lt;em&gt;did&lt;/em&gt; avoid the catastrophe at that time because I at least had a temporary branch to test the game I have uploaded. &lt;/p&gt;

&lt;h2&gt;
  
  
  THAT'S IT! NO MORE HANDICRAFT!
&lt;/h2&gt;

&lt;p&gt;(╯°□°)╯︵ ┻━┻&lt;/p&gt;

&lt;p&gt;So I launched an investigation. I knew Unity Cloud Build support webhooks. So somehow, I had to receive them and automatically download them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where&lt;/strong&gt; do I host the receiver, though?&lt;/p&gt;

&lt;p&gt;I have a rented server, but it is for serving webpages. If I had done what I'm trying to do, eventually they will shut my account down for using too much of their processing capability. Remember, I have to run the uploader provided by the publisher on the machine that has the game.&lt;br&gt;
I do have an VPS account, but they tend to be on the expensive side. I'm a broke-ass university student; Unless I want to set up a VPN or something to get a static IP, I want to avoid that.&lt;/p&gt;

&lt;p&gt;At this point I thought, "it's kind of risky, but &lt;em&gt;maybe&lt;/em&gt; I can &lt;strong&gt;try hosting it myself from my old PC and somehow expose it to the Internet.&lt;/strong&gt;"  &lt;/p&gt;

&lt;p&gt;That's when I found &lt;a href="https://loophole.cloud/" rel="noopener noreferrer"&gt;Loophole&lt;/a&gt;, a free tunneling service. If I can host an HTTP server that can receive the webhook from UCB, I can kick off automated binary downloads.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/loophole" rel="noopener noreferrer"&gt;
        loophole
      &lt;/a&gt; / &lt;a href="https://github.com/loophole/cli" rel="noopener noreferrer"&gt;
        cli
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Loophole. Instant hosting, right from your local machine. CLI.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Loophole CLI&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://loophole.cloud" rel="nofollow noopener noreferrer"&gt;https://loophole.cloud&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Loophole CLI is one of the available loophole clients.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.producthunt.com/posts/loophole?utm_source=badge-featured&amp;amp;utm_medium=badge&amp;amp;utm_souce=badge-loophole" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/73db4f96b9995f9181b2dd9a5a7b75213b02d7b2377011c8c13cbedd4f14b226/68747470733a2f2f6170692e70726f6475637468756e742e636f6d2f776964676574732f656d6265642d696d6167652f76312f66656174757265642e7376673f706f73745f69643d323830373733267468656d653d6c69676874" alt="Loophole - Instant hosting, right from your local machine | Product Hunt" width="250" height="54"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Head over to &lt;a href="https://github.com/loophole/cli/releases/latest" rel="noopener noreferrer"&gt;the releases page&lt;/a&gt; and get binary which is suitable for you.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick start&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;First create an account by executing&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ ./loophole account login
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and following the instructions there, then execute&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;# Forward application running on local port 3000 to the world
$ ./loophole http 3000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;# Forward local directory to the world
$ ./loophole path ./my-directory
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;# Forward local directory to the world using WebDAV
$ ./loophole webdav ./my-directory
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Congrats, you can now share the presented link to the world.&lt;/p&gt;
&lt;p&gt;For more information head over to &lt;a href="https://loophole.cloud/docs/" rel="nofollow noopener noreferrer"&gt;docs&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Development&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Testing&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ go test -v ./...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Running&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;# go run cli.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Building&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;# go build -o loophole cli.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/loophole/cli" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Now that the hosting method is decided, I had to learn how to listen to HTTP requests and run scripts in background simultaneously.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I make the server?
&lt;/h2&gt;

&lt;p&gt;I wanted to make this as lightweight as possible. So using apache2 sounded very exaggerated to me; that is a full-featured web server. &lt;br&gt;
Jenkins was not my option for a similar reason; if I was building the game on my machine, it would've made sense to use it. But the only goal here is to download a game and place it in the correct place. &lt;br&gt;
I just wanted something lightweight that the only thing it does is to listen to a port, and worked on the language I'm comfortable with.&lt;/p&gt;

&lt;p&gt;Since I wanted to make something in Python besides my research projects, I decided to code it in Python.&lt;/p&gt;

&lt;p&gt;Few web searches later I found &lt;a href="https://cherrypy.dev/" rel="noopener noreferrer"&gt;CherryPy&lt;/a&gt;, a lightweight web server in Python. It turns out it can safely spawn background tasks while it serves the webhook. Perfect.&lt;/p&gt;
&lt;h2&gt;
  
  
  What to download?
&lt;/h2&gt;

&lt;p&gt;This is an example of the "Buiid Successful" payload - most of the information is redacted, but you get the idea:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;artifacts&lt;/code&gt; array has several other elements for you to download, including debug symbols. I omitted all but the one whose &lt;code&gt;primary&lt;/code&gt; key is &lt;code&gt;true&lt;/code&gt;. That is our game.&lt;/p&gt;

&lt;p&gt;You can also generate secret key to check the payload - see the &lt;code&gt;x-unitycloudbuild-signature&lt;/code&gt; header.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;Several filesystem f*ck-ups later, here's my invention:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Clpsplug" rel="noopener noreferrer"&gt;
        Clpsplug
      &lt;/a&gt; / &lt;a href="https://github.com/Clpsplug/ucb-webhook-receiver" rel="noopener noreferrer"&gt;
        ucb-webhook-receiver
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Standalone Unity Cloud Build webhook receiver
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Unity Cloud Build Webhook Handler&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Powered by CherryPy&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is this?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This scripts boots a server that can accept webhook payloads from Unity Cloud Build
and handle the artifact so that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the latest artifacts are always at the specific paths&lt;/li&gt;
&lt;li&gt;the previous artifacts are archived with the timestamp at when the archive occurs.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This program was made to ensure that we don't have to download the artifacts from UCB by hand
and the correct artifacts are in the correct directories,
so that the same script can be used each time you update your game.&lt;/p&gt;
&lt;p&gt;This may be achievable with Jenkins, but I just simply wanted to write this for personal
educational purposes. So... whatevs.&lt;/p&gt;
&lt;p&gt;This script is made with SteamCMD in mind, but if you are downloading the artifacts
from Unity Cloud Build for uploading them to distributor using the similar tools,
this script is for you.&lt;/p&gt;
&lt;p&gt;Downloading them…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Clpsplug/ucb-webhook-receiver" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This project receives webhooks from UCB, downloads the artifact from them, deploys them to the output folder while adding static accompaniments, should there be any.&lt;/p&gt;

&lt;p&gt;Now I can be confident I will always deploy the correct binary! Also it was a good exercise to learn how filesystems are treated in Python.&lt;/p&gt;

&lt;p&gt;Side note: this project can be deployed on Docker! If you cannot risk your main filesystem (as you should not,) I reckon this is the safest way to run this project.&lt;/p&gt;

&lt;p&gt;Side side note: this code is not tested outside of my environment, so it may crash on you - if you experience any, issue reports are always welcome!&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>python</category>
      <category>deployment</category>
      <category>automation</category>
    </item>
    <item>
      <title>RVM did not work in the shell script, so I had to fix it</title>
      <dc:creator>C. Plug</dc:creator>
      <pubDate>Tue, 10 May 2022 07:40:23 +0000</pubDate>
      <link>https://dev.to/clpsplug/rvm-did-not-work-in-the-shell-script-so-i-had-to-fix-it-2dko</link>
      <guid>https://dev.to/clpsplug/rvm-did-not-work-in-the-shell-script-so-i-had-to-fix-it-2dko</guid>
      <description>&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;So I was building my portfolio site the other day and I decided to use &lt;a href="https://github.com/jekyll/jekyll" rel="noopener noreferrer"&gt;Jekyll&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The server I'm renting can run Ruby via RVM, so with the power of symbolic links, I can pull the source on the server, build the static site there (which can be done in a breeze,) and safely serve it to the Internet.&lt;/p&gt;

&lt;p&gt;But I ran into a problem - the script simple as &lt;em&gt;this&lt;/em&gt; did not work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-eu&lt;/span&gt;

rvm use 2.7.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RVM is not a function, selecting rubies with 'rvm use ...' will not work.

You need to change your terminal emulator preferences to allow login shell.
Sometimes it is required to use `/bin/bash --login` as the command.
Please visit https://rvm.io/integration/gnome-terminal/ for an example.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interesting, so RVM I use at the terminal prompt is &lt;em&gt;not&lt;/em&gt; &lt;code&gt;/usr/local/rvm/bin/rvm&lt;/code&gt; but a &lt;em&gt;shell function&lt;/em&gt; that gets injected as a part of the profile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Run type command directly from the shell prompt
$ type rvm
rvm is a function
(function gets printed out)

# shell script that contains `type rvm`
$ ./test.sh
rvm is /usr/local/rvm/bin/rvm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(NGL, I was fairly confused when they said "RVM is not a function..." Like, is RVM complaining that I tried to use RVM as a function when it cannot possibly be a function? Nope! What it means is that &lt;strong&gt;there is a shell function version of RVM and &lt;code&gt;rvm&lt;/code&gt; must be a function&lt;/strong&gt; to select Ruby interpreters.)&lt;/p&gt;

&lt;h2&gt;
  
  
  You need to source the profile yourselves
&lt;/h2&gt;

&lt;p&gt;It turns out &lt;a href="https://stackoverflow.com/questions/19954043/how-to-use-rvm-in-shell-scripting" rel="noopener noreferrer"&gt;you must &lt;code&gt;source&lt;/code&gt; the file provided by RVM&lt;/a&gt;. There can be two places that RVM may exist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source "$HOME/.rvm/scripts/rvm" # $HOME installation
source "/usr/local/rvm/scripts/rvm" # System installation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  But that did not quite do the trick
&lt;/h2&gt;

&lt;p&gt;Apparently, RVM relies on &lt;em&gt;unbound variables,&lt;/em&gt; so running the script with &lt;code&gt;set -eu&lt;/code&gt; crashes it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-eu&lt;/span&gt;

&lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"/usr/local/rvm/scripts/rvm"&lt;/span&gt;

rvm use 2.7.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/local/rvm/scripts/functions/support: Line 182: _system_name: Unbound variable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we need to temporarily allow such variables while we run all the RVM commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example working script
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; +u &lt;span class="c"&gt;# WTF: Avoid RVM crashing due to unbound variables&lt;/span&gt;

&lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"/usr/local/rvm/scripts/rvm"&lt;/span&gt;
rvm use 2.7.2

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-eu&lt;/span&gt; &lt;span class="c"&gt;# Restore strict error checking&lt;/span&gt;

bundle &lt;span class="nb"&gt;install
&lt;/span&gt;&lt;span class="nv"&gt;JEKYLL_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production bundle &lt;span class="nb"&gt;exec &lt;/span&gt;jekyll build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Random thought
&lt;/h2&gt;

&lt;p&gt;I remember having similar issue trying to use &lt;code&gt;pyenv&lt;/code&gt; in a Jenkins-triggered shell script... It could've been an issue of the similar nature.&lt;/p&gt;

</description>
      <category>rvm</category>
      <category>ruby</category>
      <category>jekyll</category>
    </item>
    <item>
      <title>Here is My Take on Error-resistant Way of Naming Boolean Variables</title>
      <dc:creator>C. Plug</dc:creator>
      <pubDate>Thu, 31 Mar 2022 03:11:32 +0000</pubDate>
      <link>https://dev.to/clpsplug/discussing-error-resistant-way-of-naming-boolean-variables-44p3</link>
      <guid>https://dev.to/clpsplug/discussing-error-resistant-way-of-naming-boolean-variables-44p3</guid>
      <description>&lt;h2&gt;
  
  
  Confusing bool(ean) variables
&lt;/h2&gt;

&lt;p&gt;Pretty much all of us has done something similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isAvailable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Is something in stock?&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isAvailable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Not Avaialble"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Uh oh&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Available"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Prints... "Not Available"...???&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...or, an accidental reversal of the &lt;code&gt;if&lt;/code&gt; logics.&lt;/p&gt;

&lt;p&gt;This one is very simple as the only mistake is the swapped labels. However, if the content inside of the &lt;code&gt;if&lt;/code&gt; gets bigger or in the case of &lt;code&gt;else&lt;/code&gt; being no-op, you may start to make this kind of mistakes. Heck, I still do it.&lt;/p&gt;

&lt;p&gt;But I wanted to put a stop to it and looked back all the code for the project I was working on. There I found a potential way that I can prevent some of the errors - defining a more robust naming convention.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Of course, this is not the silver bullet - some of you may even think that what I'm about to write is more confusing than ever! So use this convention at your discretions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Naming the boolean values
&lt;/h2&gt;

&lt;p&gt;Variables with type boolean can only take two values: &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt;. For this reason, most of the use-cases are to store some state that can be answered by YES/NO.&lt;/p&gt;

&lt;p&gt;Such nature of boolean usually leads us to naming them like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;is....&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;has...&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;can...&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is my base convention. When I declare a boolean value (be it local var or property,) I always prepend it with a &lt;code&gt;be&lt;/code&gt; or an auxiliary verb.&lt;/p&gt;

&lt;p&gt;This part is not much of the problem, however. It is &lt;strong&gt;the next part of the name&lt;/strong&gt; that I found a potential problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Words that explain states
&lt;/h2&gt;

&lt;p&gt;The part in question is a word or a phrase that explain what state the variable is supposed to mean. Let me call that part "State Words." I reckon that there are three categories for state words. Two of them being: &lt;strong&gt;Positive Words&lt;/strong&gt; or &lt;strong&gt;Negative Words&lt;/strong&gt;. E.g.,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Positive words

&lt;ul&gt;
&lt;li&gt;Available&lt;/li&gt;
&lt;li&gt;Succeeded&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Negative Words

&lt;ul&gt;
&lt;li&gt;Unavailable&lt;/li&gt;
&lt;li&gt;Failed&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;I have found that improper mixing of those category leads to a burst of human error in writing codes for me.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mixing the Categories
&lt;/h3&gt;

&lt;p&gt;When the values refer to &lt;em&gt;different&lt;/em&gt; states and those values use state words from different categories, it won't be an &lt;em&gt;immediate&lt;/em&gt; problem. It may be naturally done for the simplicity or the readability of the logic/code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;hasFetchFailed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Negative&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isAvailable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Positive&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasFetchFailed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Communication failed?!?"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isAvailable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Available"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Not Available"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But they still may become problematic once you start mixing them together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;hasFetchFailed&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;isAvailable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// is this when the fetch has failed or not? It is hard to deduce it within a second &lt;/span&gt;
  &lt;span class="c1"&gt;// and also, we'll have a bad time when we try to reverse this expression.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And all the hell breaks loose when those variables points to the same state, but the state words used is from different categories. This situation is much more annoying as it occurs across the code within the project, like in different classes or methods. When the state is very important in the project, referring to it using both positive state words and negative ones is just asking for problem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;hasSucceded&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This bool uses positive state word&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;hasFailed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// but this one's negative!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As I found those cases in my code base, I came to a conclusion that I probably should &lt;strong&gt;decide which category to use for common states&lt;/strong&gt;, and for others, I should &lt;strong&gt;decide once and stick with my decision all the way.&lt;/strong&gt; Below is an example, but you could also prohibit one category altogether (although this is a bit too extreme.)&lt;/p&gt;

&lt;p&gt;Ex)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;State Word(s)&lt;/th&gt;
&lt;th&gt;Reason&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Communication Result&lt;/td&gt;
&lt;td&gt;Negative&lt;/td&gt;
&lt;td&gt;failed&lt;/td&gt;
&lt;td&gt;enables early return without negating the value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stock availability&lt;/td&gt;
&lt;td&gt;Positive&lt;/td&gt;
&lt;td&gt;available&lt;/td&gt;
&lt;td&gt;Less prone to make mistakes when writing code for Views&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  What about the last category?
&lt;/h3&gt;

&lt;p&gt;At the start, I mentioned that there are three patterns for state words. The last one is, of course, words that does not fall within either of them.&lt;/p&gt;

&lt;p&gt;Since this category is pretty much the very reason I wrote this article, allow me to explain my specific situation.&lt;/p&gt;

&lt;p&gt;I created a rhythm game called &lt;a href="https://store.steampowered.com/app/1352730" rel="noopener noreferrer"&gt;Twin Horizons&lt;/a&gt;, which is played with two sets of four lanes that exist on the top and the bottom. This game provides "Full Lanes" mode where you use all the lane and "Half Lanes" mode where you use only the bottom four. Those modes are called lane styles.&lt;/p&gt;

&lt;p&gt;And this game contains a logic where &lt;strong&gt;it is important to know which lane style the player has played.&lt;/strong&gt; It is when I was looking back such part of my code base that I found something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This value exists as the parameter from the other scene&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isHalf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;???;&lt;/span&gt; &lt;span class="c1"&gt;// by which I mean "Is the player playing in Half Lanes mode?"&lt;/span&gt;

&lt;span class="c1"&gt;// ...which is used later down the logic.&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;rewardCoin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isHalf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;rewardCoin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;700&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;rewardCoin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;800&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This "state word" is &lt;strong&gt;not even positive or negative!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And then I remembered that this very state word was causing all kinds of trouble when I was working on this part.&lt;/p&gt;

&lt;p&gt;Let me put it in this way: &lt;strong&gt;What does &lt;code&gt;isHalf == false&lt;/code&gt; even &lt;em&gt;mean&lt;/em&gt;???&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Well, I just explained what the game was, so we may have some idea, but can anybody, like &lt;em&gt;literally anybody that knows nothing about the game&lt;/em&gt; realize that &lt;code&gt;isHalf == false&lt;/code&gt; means that the player is playing in Full Lanes mode?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;isHalf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// *We* know that this part is run when the "Full Lanes"&lt;/span&gt;
  &lt;span class="c1"&gt;// is played, but can *everybody&amp;amp; know?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What makes this matter worse is that this value is passed as a part of a &lt;code&gt;struct&lt;/code&gt; that contains the information from the other scenes (for context, I use Unity for this game.) As the definition cannot be changed easily, &lt;strong&gt;we are locked down to using either &lt;code&gt;isHalf&lt;/code&gt; or &lt;code&gt;isFull&lt;/code&gt;.&lt;/strong&gt;&lt;br&gt;
If in some unfortunate situation where the procedure that run only on Half and the one on Full resides in the same scene, we're gonna be in a big trouble.&lt;/p&gt;

&lt;p&gt;Some of you may have noticed: &lt;strong&gt;it may not be advisable to use boolean in this case.&lt;/strong&gt; The sheer fact to express "is the player playing with Half Lanes style?" was wrong. The fact that these would be pretty much the only two lane styles in the game for foreseeable future did not help at all.&lt;/p&gt;

&lt;p&gt;So to avoid the confusion altogether, I decided to ditch &lt;code&gt;bool&lt;/code&gt; and use &lt;code&gt;enum&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;LaneStyle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Half&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;Full&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;LaneStyle&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This forces me to write &lt;strong&gt;which style I'm talking about&lt;/strong&gt; which reduces the amount of confusion.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;LaneStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Half&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 100% for Half Lanes&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We can name variables virtually however we want, and that flexibility makes us make bad choices. So how about purposefully restricting how we name them to avoid that?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can anybody immediately know what the reverse of the state words mean?

&lt;ul&gt;
&lt;li&gt;If yes... (e.g., Available --Negated--&amp;gt; Unavailable)&lt;/li&gt;
&lt;li&gt;Variables that points to the same state should be using the same state words - don't mix words from both categories&lt;/li&gt;
&lt;li&gt;If no...&lt;/li&gt;
&lt;li&gt;Consider &lt;em&gt;not&lt;/em&gt; using boolean and try enum&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Rules simple as this may help you write readable code and avoid human errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extra talks (rants?)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;!&lt;/code&gt; for negating bool being somewhat easy to miss
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;isPlayable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// I sometimes get confused b/c I did not notice &lt;/span&gt;
  &lt;span class="c1"&gt;// the "!" at the start because the font is bad&lt;/span&gt;
  &lt;span class="c1"&gt;// And when "!" is in between parentheses, well......&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When negating a boolean property of a class instance, the &lt;code&gt;!&lt;/code&gt; gets &lt;em&gt;physically&lt;/em&gt; farther from the actual property name
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// When you only read `isActive` part...&lt;/span&gt;
  &lt;span class="c1"&gt;// well, say goodbye to your sanity&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>boolean</category>
      <category>namingconvention</category>
    </item>
    <item>
      <title>How to force Unity to target x64 or ARM64 for macOS builds</title>
      <dc:creator>C. Plug</dc:creator>
      <pubDate>Thu, 24 Dec 2020 15:52:17 +0000</pubDate>
      <link>https://dev.to/clpsplug/how-to-force-unity-to-target-x64-or-arm64-for-macos-builds-2e5a</link>
      <guid>https://dev.to/clpsplug/how-to-force-unity-to-target-x64-or-arm64-for-macos-builds-2e5a</guid>
      <description>&lt;p&gt;Unity 2020.2 adds support for Apple Silicon binaries (both native &amp;amp; Universal 2.) This means we need to decide which CPU type to use when building our game, either by hand or by code. How do you do this by code?  &lt;/p&gt;

&lt;h1&gt;
  
  
  TL;DR
&lt;/h1&gt;

&lt;p&gt;The API for switching the CPU type is not directly exposed as of 2.1f1, but you can use this workaround:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEditor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// All but the last argument must be as they appear&lt;/span&gt;
&lt;span class="n"&gt;EditorUserBuildSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetPlatformSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"Standalone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"OSXUniversal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Architecture"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"x64"&lt;/span&gt; &lt;span class="c1"&gt;// Possible values: "x64" "ARM64" "x64ARM64"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Why
&lt;/h1&gt;

&lt;p&gt;My project is built via Jenkins, which means the builds are kicked from the command line arguments.&lt;br&gt;&lt;br&gt;
Apparently, when you update to Unity 2020.2, the CPU type defaults to Universal 2 (x64 + ARM64.) However, it's often the case that you want not to use ARM64 because of the libraries you use. And it &lt;em&gt;was&lt;/em&gt; the case for me.&lt;/p&gt;
&lt;h1&gt;
  
  
  How?
&lt;/h1&gt;

&lt;p&gt;So I dug into my project files to find out that &lt;code&gt;${PROJECT_ROOT}/Library/EditorUserBuildSettings.asset&lt;/code&gt; remembers my build settings. This was bad news because this file was ignored by Git and I had three separate repository clones - one for development, the rest for building (to build dev/prod in parallel.) I needed to somehow replicate this file from the code!&lt;/p&gt;

&lt;p&gt;I opened this asset file thinking this was a YAML file to find it being a &lt;em&gt;binary&lt;/em&gt; file, but a large portion of it could be read as ASCII. I found this in the last of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Standalone....iPhone....OSXUniversal....Architecture....x64....CreateXcodeProject....false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(this portion contained a &lt;strong&gt;&lt;em&gt;lot&lt;/em&gt;&lt;/strong&gt; of non-printing chars, which was replaced with &lt;code&gt;....&lt;/code&gt;. The number of periods is &lt;em&gt;not&lt;/em&gt; to scale.)&lt;/p&gt;

&lt;p&gt;Unfortunately, Unity does not expose these variables as an API, but there is &lt;a href="https://docs.unity3d.com/2020.2/Documentation/ScriptReference/EditorUserBuildSettings.SetPlatformSettings.html" rel="noopener noreferrer"&gt;a method you can tap into these raw values&lt;/a&gt;. The linked documentation is for one of the overloads, but you also have this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;EditorUserBuildSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetPlatformSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;buildTargetGroupStr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builTargetStr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settingName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settingValue&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As for &lt;code&gt;buildTargetGroupStr&lt;/code&gt; etc., you need to set it as it appears in the .asset file - making the method look like the first code block.&lt;/p&gt;

&lt;p&gt;Put that code in one of your &lt;code&gt;IPreprocessBuildWithReport&lt;/code&gt; implementation, and you should be good to go.&lt;/p&gt;

&lt;p&gt;Do keep in mind though, if you have this code in your project, you will &lt;strong&gt;&lt;em&gt;not&lt;/em&gt;&lt;/strong&gt; be able to specify your CPU type from the Build Settings window (it'll be ignored!)&lt;/p&gt;




&lt;p&gt;Corrections are welcome, I wrote this late at night :P&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>applesilicon</category>
      <category>m1</category>
    </item>
    <item>
      <title>Seriously, periodically do brew cleanup.</title>
      <dc:creator>C. Plug</dc:creator>
      <pubDate>Tue, 13 Nov 2018 02:28:54 +0000</pubDate>
      <link>https://dev.to/clpsplug/seriously-periodically-do-brew-cleanup-36bi</link>
      <guid>https://dev.to/clpsplug/seriously-periodically-do-brew-cleanup-36bi</guid>
      <description>&lt;p&gt;&lt;strong&gt;EDIT:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Seems like that &lt;a href="https://brew.sh/2019/02/02/homebrew-2.0.0/" rel="noopener noreferrer"&gt;since v2.0.0, homebrew decided that it should perform auto cleanup every 30 days,&lt;/a&gt; so it is rare to run into issues like below nowadays :) I'm keeping this up for historical reason (and possibly for other softwares that don't auto-cleanup themselves.)&lt;/p&gt;

&lt;p&gt;I just found out that my Homebrew was keeping all the old installer for my upgradable Casks 😱&lt;/p&gt;

&lt;p&gt;I ran &lt;code&gt;brew cleanup&lt;/code&gt; to find to my horror:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_( _・ω)_&amp;lt;(me XD)@localhost H30 11/12 12:13:17)
&amp;gt; brew cleanup                                                                [~]
Removing: /usr/local/Cellar/apr/1.6.3... (60 files, 1.3MB)
Removing: /usr/local/Cellar/arpack/3.6.2... (22 files, 1.4MB)
...
Removing: /Users/(me XD)/Library/Caches/Homebrew/Cask/unity--2018.2.1f1,1a9968d9f99c.pkg... (940.3MB)
Removing: /Users/(me XD)/Library/Caches/Homebrew/Cask/unity--2018.2.6f1,c591d9a97a0b.pkg... (935.7MB)
...
Removing: /Users/(me XD)/Library/Caches/Homebrew/Cask/unity--2018.2.13f1,83fbdcd35118.pkg... (944.6MB)
Removing: /Users/(me XD)/Library/Caches/Homebrew/Cask/unity--2017.3.1f1,fc1d3344e6ea.pkg... (721.0MB)
Removing: /Users/(me XD)/Library/Caches/Homebrew/Cask/unity--2018.2.12f1,0a46ddfcfad4.pkg... (935.6MB)
Removing: /Users/(me XD)/Library/Caches/Homebrew/Cask/unity--2018.1.0f2,d4d99f31acba.pkg... (943.8MB)
...
==&amp;gt; This operation has freed approximately 19.9GB of disk space.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;19.9GB?!?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I only have 250GB of space in total; that's a big chunk of data. If you are using Homebrew Cask to install your favorite apps, be sure to do &lt;code&gt;brew cleanup&lt;/code&gt; (or use flag &lt;code&gt;--cleanup&lt;/code&gt; on upgrades!)&lt;/p&gt;

</description>
      <category>homebrew</category>
    </item>
  </channel>
</rss>
