<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>cheehow.dev Blog</title>
        <link>https://www.cheehow.dev/blog</link>
        <description>cheehow.dev Blog</description>
        <lastBuildDate>Sat, 28 Oct 2023 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[TypeScript object types with optional and minimally required properties]]></title>
            <link>https://www.cheehow.dev/blog/2023/10/28/typescript-object-types-with-optional-and-minimally-required-properties</link>
            <guid>https://www.cheehow.dev/blog/2023/10/28/typescript-object-types-with-optional-and-minimally-required-properties</guid>
            <pubDate>Sat, 28 Oct 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[How to create an object type in TypeScript with optional properties that has at least one required property. ]]></description>
            <content:encoded><![CDATA[<h3 class="anchor anchorWithStickyNavbar_LWe7" id="tldr">TL;DR<a href="https://www.cheehow.dev/blog/2023/10/28/typescript-object-types-with-optional-and-minimally-required-properties#tldr" class="hash-link" aria-label="Direct link to TL;DR" title="Direct link to TL;DR">​</a></h3>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Solution 1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">LabelEntry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">ImageEntry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Entry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> LabelEntry </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> ImageEntry</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Solution 2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Entry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token string" style="color:#e3116c">'label'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'image'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>An object type that I find myself creating very frequently is one that has one or all of several properties. For example, I can create an entry with a text label, one with an image, or one with both:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> textEntry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Fluffy cloud'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> imgEntry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'cloud.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> bothEntry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Fluffy cloud'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'cloud.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-problem">The problem<a href="https://www.cheehow.dev/blog/2023/10/28/typescript-object-types-with-optional-and-minimally-required-properties#the-problem" class="hash-link" aria-label="Direct link to The problem" title="Direct link to The problem">​</a></h2>
<p>Intuituively, I would declare the type for this kind of objects to be like this:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Entry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>There's a problem with this type. You can see the problem in the next listing with <code>entry3</code>:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> entry1</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Entry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Fluffy cloud'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> entry2</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Entry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'cloud.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> entry3</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Entry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// We don't want to allow this to happen.</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>With this type definition, <code>entry3</code> can be assigned an empty object. This is <em>not</em> the outcome that we want.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="solution-1">Solution 1<a href="https://www.cheehow.dev/blog/2023/10/28/typescript-object-types-with-optional-and-minimally-required-properties#solution-1" class="hash-link" aria-label="Direct link to Solution 1" title="Direct link to Solution 1">​</a></h2>
<p>One solution to the problem is to create two types and create an <a href="https://www.typescriptlang.org/docs/handbook/2/objects.html#intersection-types" target="_blank" rel="noopener noreferrer">intersection</a> type like so:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">LabelEntry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">ImageEntry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Entry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> LabelEntry </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> ImageEntry</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The <code>entry3</code> variable above will show an error <code>Type '{}' is not assignable to type 'Entry'.</code> because it contains an empty object.</p>
<p>Instead it must have either one (or both) <code>label</code> or <code>image</code> as its property.</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> entry1</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Entry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Fluffy cloud'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> entry2</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Entry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'cloud.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> entry3</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Entry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Fluffy cloud'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'cloud.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="solution-2">Solution 2<a href="https://www.cheehow.dev/blog/2023/10/28/typescript-object-types-with-optional-and-minimally-required-properties#solution-2" class="hash-link" aria-label="Direct link to Solution 2" title="Direct link to Solution 2">​</a></h2>
<p>If coming up with names is not your strongest forte or you want to have fewer redundant lines of code, this might be your preferred solution:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Entry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token string" style="color:#e3116c">'label'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'image'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><code>Record</code> is an utility type that helps to define the keys and values of an object type easily.</p>
<blockquote>
<p>P.S. A mistake that I made before was using union (<code>|</code>) instead of intersection (<code>&amp;</code>) for the key values (i.e. <code>Record&lt;'label' | 'image', string&gt;</code>). This would have made <code>entry1</code> and <code>entry2</code> invalid.</p>
</blockquote>]]></content:encoded>
            <category>knowledgebase</category>
            <category>typescript</category>
            <category>union</category>
            <category>intersection</category>
            <category>typing</category>
            <category>optional properties</category>
        </item>
        <item>
            <title><![CDATA[Auto-increment field with Prisma]]></title>
            <link>https://www.cheehow.dev/blog/2023/10/17/autoincrement-field-with-prisma</link>
            <guid>https://www.cheehow.dev/blog/2023/10/17/autoincrement-field-with-prisma</guid>
            <pubDate>Tue, 17 Oct 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[How to fix conflict with auto-increment ID field with Prisma and PostgreSQL ]]></description>
            <content:encoded><![CDATA[<p><img decoding="async" loading="lazy" alt="SELECT setval(pg_get_serial_sequence(&amp;#39;tablename&amp;#39;, &amp;#39;id&amp;#39;), coalesce(max(id)+1, 1), false) FROM &amp;quot;tablename&amp;quot;;" src="https://www.cheehow.dev/assets/images/hero-cbc6ebfbed7739a257077c1cad14cc27.png" width="1012" height="202" class="img_ev3q"></p>
<p>This post is a knowledgebase article on <a href="https://www.prisma.io/" target="_blank" rel="noopener noreferrer">Prisma</a> with <a href="https://www.postgresql.org/" target="_blank" rel="noopener noreferrer">PostgreSQL</a>.</p>
<p>The typical model in a Prisma schema has an <code>id</code> field that auto-increments:</p>
<div class="language-prisma codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-prisma codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">model User {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  id Int @id @default(autoincrement())</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  name String</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The following is working (most of the time) code that inserts a new entry:</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">prisma</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">user</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">data</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Some User'</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>However, the following error may occur:</p>
<p>Unique constraint failed on the fields: (<code>id</code>)</p>
<p>This is baffling - if the field auto-increments, how can the unique constraint be violated?</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="why">Why?<a href="https://www.cheehow.dev/blog/2023/10/17/autoincrement-field-with-prisma#why" class="hash-link" aria-label="Direct link to Why?" title="Direct link to Why?">​</a></h3>
<p>The answer (for PostgreSQL at least) is that this error typically happens if there is an entry created before that was <em>not</em> created using the auto-incremented ID. In other words, if there is an entry that was created where the ID was explicitly set, a conflict arises when Prisma tries to set its own auto-incremented ID.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="solution">Solution<a href="https://www.cheehow.dev/blog/2023/10/17/autoincrement-field-with-prisma#solution" class="hash-link" aria-label="Direct link to Solution" title="Direct link to Solution">​</a></h3>
<p>So, where possible, avoid setting the ID explicitly for tables which have the primary key field being an auto-incremented number field.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="but-what-about">But what about...<a href="https://www.cheehow.dev/blog/2023/10/17/autoincrement-field-with-prisma#but-what-about" class="hash-link" aria-label="Direct link to But what about..." title="Direct link to But what about...">​</a></h3>
<p>Alright, so we know what to avoid doing in the future. But is there a solution for tables that already have entries with manual IDs created?</p>
<p>As a matter of fact, there is!</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> setval</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">pg_get_serial_sequence</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'"User"'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'id'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">coalesce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">+</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"User"</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Notice that the table name is encapsulated within a pair of single quotes and a pair of double quotes (<code>'"User"'</code>)? This is because the name of the table begins with an uppercase character (<code>U</code>). This is a quirk of PostgreSQL. If the table name does not begin with an uppercase letter, the inner double quotes is not necessary (e.g. <code>'user'</code>).</p>
<p>See this discussion in <a href="https://github.com/prisma/prisma/discussions/5256" target="_blank" rel="noopener noreferrer">Prisma's Github Discussions</a>.</p>]]></content:encoded>
            <category>knowledgebase</category>
            <category>prisma</category>
            <category>postgresql</category>
            <category>programming</category>
            <category>autoincrement</category>
        </item>
        <item>
            <title><![CDATA[Docusaurus with Google Authentication]]></title>
            <link>https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication</link>
            <guid>https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication</guid>
            <pubDate>Sun, 02 Apr 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[With a little bit of programming, you can restrict your site made by Docusaurus to be accessible to users signed in to Google.]]></description>
            <content:encoded><![CDATA[<p>With a little bit of programming, your site made by Docusaurus can be modified to be accessible only to users signed in to Google.</p>
<p>The source material came from this <a href="https://medium.com/@thomasdevshare/docusaurus-authentication-with-firebase-c824da24bc51" target="_blank" rel="noopener noreferrer">article</a> by <a href="https://medium.com/@thomasdevshare/about" target="_blank" rel="noopener noreferrer">Thomasdevshare</a>. His article describes a similar authentication scheme for Docusaurus with Firebase as the identity provider whereas this article describes the same approach using Google API directly.</p>
<!-- -->
<p>The main concepts described in this article will be largely the same as that written by Thomas. The main differences:</p>
<ul>
<li>instead of depending on the <a href="https://www.npmjs.com/package/firebase" target="_blank" rel="noopener noreferrer">Firebase package</a>, the <a href="https://www.npmjs.com/package/@react-oauth/google" target="_blank" rel="noopener noreferrer"><code>@react-oauth</code> package</a> is used, and</li>
<li>a new section on designating allowed users to access the page.</li>
</ul>
<p>(The example in this document is written in TypeScript but it should be easily applicable to JavaScript.)</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="pre-requisites">Pre-requisites<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication#pre-requisites" class="hash-link" aria-label="Direct link to Pre-requisites" title="Direct link to Pre-requisites">​</a></h2>
<p>These are the things that you need to set up:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-google-credential">1. Google credential<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication#1-google-credential" class="hash-link" aria-label="Direct link to 1. Google credential" title="Direct link to 1. Google credential">​</a></h3>
<p>This step can be done at <a href="https://console.cloud.google.com/apis/credentials" target="_blank" rel="noopener noreferrer">https://console.cloud.google.com/apis/credentials</a></p>
<p>Follow the <a href="https://developers.google.com/identity/protocols/oauth2/javascript-implicit-flow#enable-apis" target="_blank" rel="noopener noreferrer">Google instructions</a> to configure your project and create a <em>client ID for Web application</em>.</p>
<p>For local development, add <code>http://localhost</code> and <code>http://localhost:&lt;port_number&gt;</code> to the Authorized JavaScript origins for <code>@react-oauth</code> to work. When deploying to production, specify the actual URL of your site.</p>
<p>Note the <code>Client ID</code> field for the OAuth 2.0 Client - this needs to be placed into the <em>.env</em> file (see <a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication#3-specify-google-client-id-and-allowed-users">below</a>).</p>
<p><img decoding="async" loading="lazy" alt="Google OAuth 2.0 Client" src="https://www.cheehow.dev/assets/images/google-client-id-9dd28efc186c086516c3040c090a51fe.png" width="800" height="78" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-add-the-react-oauthgoogle-dependency">2. Add the <a href="https://www.npmjs.com/package/@react-oauth/google" target="_blank" rel="noopener noreferrer"><code>@react-oauth/google</code></a> dependency<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication#2-add-the-react-oauthgoogle-dependency" class="hash-link" aria-label="Direct link to 2-add-the-react-oauthgoogle-dependency" title="Direct link to 2-add-the-react-oauthgoogle-dependency">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">npm i @react-oauth/google</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This dependency makes it easy to incorporate the Google SSO implicit-authorization flow.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-specify-google-client-id-and-allowed-users">3. Specify Google Client ID and allowed users<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication#3-specify-google-client-id-and-allowed-users" class="hash-link" aria-label="Direct link to 3. Specify Google Client ID and allowed users" title="Direct link to 3. Specify Google Client ID and allowed users">​</a></h3>
<p>Create a file <em>.env</em> in the root of the directory (same location as <em>docusaurus.config.js</em>) and add the following contents, replacing the text in arrow brackets with actual values:</p>
<div class="tabs-container tabList__CuJ"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_LNqP tabs__item--active">.env</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">Example</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_Ymn6"><pre><code><p>GOOGLE_CLIENTID=&lt;google client ID&gt;</p><br><p>ALLOWED_USERS=&lt;email addresses separated by commas&gt;</p></code></pre></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""><pre><code><p>GOOGLE_CLIENTID=1111111111111-djfh38dhf467as1hdgg3f2df334msd.apps.googleusercontent.com</p><br><p>ALLOWED_USERS=<a href="mailto:user1@example.com" target="_blank" rel="noopener noreferrer">user1@example.com</a>, <a href="mailto:user2@example.com" target="_blank" rel="noopener noreferrer">user2@example.com</a>, <a href="mailto:user3@example.com" target="_blank" rel="noopener noreferrer">user3@example.com</a></p></code></pre></div></div></div>
<p>The Google credentials obtained in <a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication#1-google-credential">Step 1</a> should replace <code>&lt;google client ID&gt;</code>.</p>
<p><code>&lt;email addresses separated by commas&gt;</code> should be replaced with actual email addresses e.g. <code>email1@example.com, email2@example.com</code></p>
<p>(The space after the comma will be trimmed by the plugin so it doesn't matter if the commas are followed by spaces.)</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="4-configure-docusaurusconfigjs-to-read-the-environment-variables">4. Configure <em>docusaurus.config.js</em> to read the environment variables<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication#4-configure-docusaurusconfigjs-to-read-the-environment-variables" class="hash-link" aria-label="Direct link to 4-configure-docusaurusconfigjs-to-read-the-environment-variables" title="Direct link to 4-configure-docusaurusconfigjs-to-read-the-environment-variables">​</a></h3>
<p>Docusaurus is only able to read the environment variable during pre-processing. This means that the values in the <em>.env</em> file have to be "transferred" to the configuration file.</p>
<p>This is done by first adding the following line to <em>docusaurus.config.js</em>:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'dotenv'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">config</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Then, somewhere in the file below, assign the process environment variables to properties under <code>customFields</code>:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> config </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">title</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Me3 Technical Documentation'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">customFields</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">allowedUsers</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">env</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">ALLOWED_USERS</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">googleClientId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">env</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">GOOGLE_CLIENTID</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>I had used the plugin <a href="https://npmjs.com/package/docusaurus2-dotenv" target="_blank" rel="noopener noreferrer">docusaurus2-dotenv</a> before but it didn't work with <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-docusaurus-site/" target="_blank" rel="noopener noreferrer">deployment to Cloudflare Pages</a>.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="log-in-component">Log-in Component<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication#log-in-component" class="hash-link" aria-label="Direct link to Log-in Component" title="Direct link to Log-in Component">​</a></h2>
<p>Next create the log-in component. This component displays the Google sign-in button for the user to authenticate himself/herself.</p>
<p>Create a file <em>src/components/login-google/index.tsx</em></p>
<div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">src/components/login-google/index.tsx</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">useDocusaurusContext</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@docusaurus/useDocusaurusContext"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports">  </span><span class="token imports maybe-class-name">CredentialResponse</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports">  </span><span class="token imports maybe-class-name">GoogleLogin</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports">  </span><span class="token imports maybe-class-name">GoogleOAuthProvider</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports"></span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@react-oauth/google'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">React</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">LoginGoogle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">props</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">login</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  denied</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> boolean</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">siteConfig</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> customFields </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useDocusaurusContext</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> clientId </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> customFields</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">googleClientId</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">as</span><span class="token plain"> string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">handleError</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Failed to sign in with Google.'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">handleSuccess</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter literal-property property" style="color:#36acaa">creds</span><span class="token parameter operator" style="color:#393A34">:</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">CredentialResponse</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> plaintext </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">decode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">creds</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">credential</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">plaintext</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> payload </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">JSON</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">parse</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">plaintext</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">isAllowed</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">payload</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">email</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      props</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">login</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">payload</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">email</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      props</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">login</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Checks if the supplied email address is allowed to see the page.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">isAllowed</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter literal-property property" style="color:#36acaa">email</span><span class="token parameter operator" style="color:#393A34">:</span><span class="token parameter"> string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> boolean </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> allowedUsers </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> customFields</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">allowedUsers</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"string"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      allowedUsers </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> customFields</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">allowedUsers</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">split</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">","</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">trim</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">allowedUsers</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">includes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">email</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">GoogleOAuthProvider</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">clientId</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">clientId</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">        </span><span class="token tag attr-name" style="color:#00a4db">style</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">          </span><span class="token tag script language-javascript literal-property property" style="color:#36acaa">display</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'flex'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">          </span><span class="token tag script language-javascript literal-property property" style="color:#36acaa">flexFlow</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'column nowrap'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">          </span><span class="token tag script language-javascript literal-property property" style="color:#36acaa">alignItems</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'center'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">          </span><span class="token tag script language-javascript literal-property property" style="color:#36acaa">margin</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'5rem auto'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">          </span><span class="token tag script language-javascript literal-property property" style="color:#36acaa">textAlign</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'center'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">        </span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">      </span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">h2</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">Please sign in to your Google account to get access.</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">h2</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">props</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">denied</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">em</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">Not authorised</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">em</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">GoogleLogin</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">            </span><span class="token tag attr-name" style="color:#00a4db">onSuccess</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">handleSuccess</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">            </span><span class="token tag attr-name" style="color:#00a4db">onError</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">handleError</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">          </span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">GoogleLogin</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">GoogleOAuthProvider</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Function to decode the JWT from Google to get the user's email address.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">decode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter literal-property property" style="color:#36acaa">jwt</span><span class="token parameter operator" style="color:#393A34">:</span><span class="token parameter"> string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> string </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> parts </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> jwt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">split</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">''</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">atob</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parts</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="swizzle-the-root-component"><em>Swizzle</em> the Root Component<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication#swizzle-the-root-component" class="hash-link" aria-label="Direct link to swizzle-the-root-component" title="Direct link to swizzle-the-root-component">​</a></h2>
<p><a href="https://docusaurus.io/docs/swizzling" target="_blank" rel="noopener noreferrer"><em>Swizzling</em></a> is a term describing the overridding of an existing component with a custom implementation of it.</p>
<p>The Root component is the component to swizzle as it covers all generated pages.</p>
<div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">src/theme/Root.tsx</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">React</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> useState </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">LoginGoogle</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@site/src/components/login-google'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Root</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter punctuation" style="color:#393A34">{</span><span class="token parameter"> children </span><span class="token parameter punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// `email` is used to determine if user is allowed.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">email</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setEmail</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">useState </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">''</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">email</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">LoginGoogle</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">login</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">setEmail</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">denied</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">email </span><span class="token tag script language-javascript operator" style="color:#393A34">===</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript keyword null nil" style="color:#00009f">null</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">LoginGoogle</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">children</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>One thing to note: the authentication information is only persisted in memory. What this means is that the authentiction is temporary (the correct term is <em>ephemeral</em>). The implication is that as soon as the user refreshes the page, the authenticated information (i.e. email address) is lost and the user gets "logged out".</p>]]></content:encoded>
            <category>programming</category>
            <category>docusaurus</category>
            <category>google</category>
        </item>
        <item>
            <title><![CDATA[About Domain Names]]></title>
            <link>https://www.cheehow.dev/blog/2019/08/26/about-domain-names</link>
            <guid>https://www.cheehow.dev/blog/2019/08/26/about-domain-names</guid>
            <pubDate>Mon, 26 Aug 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[This piece is a quick, non-technical introduction to domain names.]]></description>
            <content:encoded><![CDATA[<figure><img src="https://www.cheehow.dev/assets/images/kobu-agency-7okkFhxrxNw-unsplash-8bf991280e18f3cb46cb72b1cfe0f29b.jpg" alt="two women talking while looking at laptop computer"><figcaption>Photo by <a target="_blank" href="https://unsplash.com/@kobuagency">Kobu Agency</a> on <a target="_blank" href="https://unsplash.com/search/photos/website">Unsplash</a></figcaption></figure>
<p>This piece is a quick, non-technical introduction to domain names.</p>
<p>When I set out to write this article, I did not expect to write several drafts only to completely throw them away.</p>
<p>As I planned the outline of the article, I began to realise the depth and complexity of the topic. It was a challenge not to turn this into a technical write-up on DNS and nameservers in my attempt to elucidate the jargon and economics surrounding domain names.</p>
<p>So I decided to take on a consulting mindset for writing this article. I began with the question "What is the first thing that a small business owner would ask about his/her domain?"</p>
<p>The answer?</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="cost">Cost<a href="https://www.cheehow.dev/blog/2019/08/26/about-domain-names#cost" class="hash-link" aria-label="Direct link to Cost" title="Direct link to Cost">​</a></h2>
<p>The first thing that comes to mind for any small business owner is cost. It is only natural—even expected—that, as a (potential) business owner, you want to keep costs low as much as possible.</p>
<p>So let's start with that.</p>
<p>There are two types of costs you need to be concerned with: the acquisition cost and the renewal cost.</p>
<p>The acquisition cost is based on the domain name you want. For available domain names (names not yet claimed by anyone), the cost is very affordable - less than a hundred Sing dollars. You can purchase available domains on-the-spot easily with a credit card.</p>
<p>Then there are domain names that are held for sale. These domain names are kept for no other purpose than profit. This practice is known as <em>cybersquatting</em>.</p>
<p>I have not had to purchase a domain from cybersquatters before but the lowest price you are looking at is typically a four-figure sum. For comparison, a fresh .com domain costs around US$15. This huge price difference is why all my clients and friends have chosen to brainstorm for a fresh domain rather than to shelve out large sums of money to get an existing one. If cost savings is important to you, this is what I would recommend as well.</p>
<p>For a new domain, the renewal price is usually the same as what you paid for. That has changed now—there are <em>tiered price domains</em> that are sold at a higher price than what it costs to renew them.</p>
<p>So if there is a domain name that you very much want, but comes with a higher price tag, take a look again. The difference might be small enough (some might be a few hundred dollars) for you to stomach the one-time acquisition cost if the renewal cost is nominal. (See next section for examples.) Just chalk it off as a capital expenditure. 🤷🤷‍♂️</p>
<p>The renewal cost of a domain is usually based on its top-level domain (TLD). In simple terms, the TLD is the right most part of a domain name.</p>
<p><img decoding="async" loading="lazy" alt="www.example.com" src="https://www.cheehow.dev/assets/images/example-450f2af877aeb0d7d67fc6fb0324cd63.png" width="800" height="300" class="img_ev3q"></p>
<p>You should be familiar with .com - it is the most common TLD. Together with it, .net and .org are among the earliest TLDs introduced to the domain name system (DNS).</p>
<p>There are others, but I will only go through the types that are of relevance to this article in the next section on…</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="types-of-domain-names">Types of Domain Names<a href="https://www.cheehow.dev/blog/2019/08/26/about-domain-names#types-of-domain-names" class="hash-link" aria-label="Direct link to Types of Domain Names" title="Direct link to Types of Domain Names">​</a></h2>
<p>As mentioned in the previous section, .com, .net and .org are among the earliest domains introduced in the DNS. Coincidentally, they are also the cheapest to renew.</p>
<p>Acquiring them is not easy though. Being the earliest TLDs, they are also the most used. I think it is safe to say that any English word you can think of, the .com domain is probably taken.</p>
<p>If you can think of a new word or phrase then you will be able to get the .com easily without paying a premium.</p>
<p>To combat this shortage of names, ICANN has created other TLDs such as .app, .tech, .club, etc. For these TLDs though, some unclaimed domains already command a premium right out the gate. As mentioned previously these are tiered price domains. Below are a few examples of them:</p>
<p><img decoding="async" loading="lazy" alt="domain names" src="https://www.cheehow.dev/assets/images/names-68d007ca9294c45ac2baf1384de0a847.png" width="701" height="189" class="img_ev3q"></p>
<figure><figcaption>Notice how some renewal prices are the same as the initial acquisition cost, and some are different.</figcaption></figure>
<p>My friends and customers target primarily the Singapore market. For them, either a .com or .sg/.com.sg TLD works fine. However, I do think that a .sg/.com.sg domain removes the ambiguity altogether for your target audience. In a way, it acts as a filter for traffic coming to your website, and for your audience, an implicit assurance that you are operating in Singapore.</p>
<p>Domains that end with a country specific suffix like .sg have <em>country code top-level domains</em> (ccTLDs). A ccTLD domain is likely more expensive than a generic TLD like .com, the reason being that the ccTLD has to be administered by a country-specific intermediary called a Network Information Centre. For Singapore, this entity is called SGNIC.</p>
<p>To have an idea of the kind of price difference, a typical .com domain costs around S$18 (US$13). A typical .sg/.com.sg costs around S$45.</p>
<p>Domains ending with .com.sg can only be registered by a Singaporean company entity. Domains ending with .sg may be registered by anyone residing in Singapore. To get a Singapore ccTLD, there is an additional verification of identity implemented by the VerifiedID@SG scheme. Singaporeans can access this scheme using their SingPass accounts.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="getting-the-domain-name">Getting the Domain Name<a href="https://www.cheehow.dev/blog/2019/08/26/about-domain-names#getting-the-domain-name" class="hash-link" aria-label="Direct link to Getting the Domain Name" title="Direct link to Getting the Domain Name">​</a></h2>
<p>Most of you reading this would probably leave it to your appointed vendor to register the domain for you. This is totally fine, if your vendor is reliable.</p>
<p>As mentioned in the <a href="https://www.cheehow.dev/blog/2019/08/15/3-things-to-watch-out-for-when-commissioning-your-website/">previous article</a>, it is important that the registrant information is registered as your own.</p>
<p>The following scenario that I am going to describe is a worst-case scenario that I have not had to deal with yet.</p>
<p>Suppose your vendor registered his/her own information for all four pieces of information (billing, tech, admin, and registrant) for the domain (probably for no other reason than for convenience). If your vendor is a solopreneur/freelancer, all formal records would show that he/she is the sole registrant. In the event that he/she is not contactable for whatever reason, imagine how would you recover your domain?</p>
<p>Now, I am not saying that having your name lodged as the registrant will guarantee that you can recover your domain. But not having your name in any of the records will definitely not help you at all.</p>
<p>Therefore, you have to emphasize to your vendor/developer to make sure to enter your information for the registrant. Incidentally, if you are getting a .sg or .com.sg domain, you are required by the VerifiedID@SG scheme to verify your identity using your SingPass account. Note that this is <strong>in addition</strong> to the registrant info, so be sure that both are in order.</p>
<p>If you are inclined, it is perfectly fine for you to register the domain name by yourself. But be aware that at some point, you will need to map the DNS records for your domain to the server where your website resides. Alternatively, rather than doing it yourself, you may also pass your credentials to your vendor to make those changes for you.</p>
<p>What I recommend though (if you registered the domain name yourself) is to have your vendor change those settings in front of you. On the day when you "go live" (i.e. putting your website online), have the vendor come to your office. Sign in to your registrar's control panel, and let him/her change the DNS settings on the spot. This way, you need not reveal your password and worry about potential security issues.</p>
<p>I will not be describing the DNS settings in this article. It is too complex to describe in a reasonable length. You should leave this part to your vendor/developer to handle.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="www-or-not">WWW or not?<a href="https://www.cheehow.dev/blog/2019/08/26/about-domain-names#www-or-not" class="hash-link" aria-label="Direct link to WWW or not?" title="Direct link to WWW or not?">​</a></h2>
<p>The last thing to mention is the www prefix. Unbeknownst to many, the www prefix, known as a <em>subdomain</em>, is an optional part of the domain name that is determined by your DNS settings.</p>
<p>From what I understand, this prefix also has an impact on your search rankings. Depending on configurations, it is possible to have your website served on both the www and naked domain (i.e. without the www). Google seems to frown upon this though - it considers them to be duplicate content. How it affects your website's ranking in the search results, I'm not exactly sure. All I know is that Google recommends not having the same content at different URLs. The naked domain and the www subdomain are considered different URLs.</p>
<p>My recommendation is that you ask your developer to redirect traffic from one to the other. It is usually a matter of preference whether to serve your website on the naked domain or the subdomain. My stance is that having a www subdomain makes it absolutely clear that what you are referring to is a website. This is all the more important if your chosen TLD is not a .com (e.g. <a href="http://www.example.app/" target="_blank" rel="noopener noreferrer">www.example.app</a>, <a href="http://www.example.tech/" target="_blank" rel="noopener noreferrer">www.example.tech</a>, etc.)</p>
<p>Note that I am recommending the www prefix for your website, not your email address. It is absolutely unnecessary to have the prefix for your email address. In fact it is cumbersome to include the prefix for your email address. (Compare <a href="mailto:charles@school.com" target="_blank" rel="noopener noreferrer">charles@school.com</a> and <a href="mailto:charles@www.school.com" target="_blank" rel="noopener noreferrer">charles@www.school.com</a>)</p>
<p>This article has gone on long enough already. If the opportunity arises, I will discuss domain transfer and other topics in another article.</p>
<p>(Also posted on <a href="https://medium.com/@cheehow_c/about-domain-names-5cfd9cc9af40?sk=97bc4b798071fd59ce73b4d7defb4325" target="_blank" rel="noopener noreferrer">Medium</a> and <a href="https://www.linkedin.com/pulse/domain-names-chee-how-chua" target="_blank" rel="noopener noreferrer">LinkedIn</a>.)</p>]]></content:encoded>
            <category>websitetips</category>
            <category>domains</category>
            <category>sme</category>
            <category>smallbusiness</category>
        </item>
        <item>
            <title><![CDATA[3 Things to Watch Out For When Commissioning Your Website]]></title>
            <link>https://www.cheehow.dev/blog/2019/08/15/3-things-to-watch-out-for-when-commissioning-your-website</link>
            <guid>https://www.cheehow.dev/blog/2019/08/15/3-things-to-watch-out-for-when-commissioning-your-website</guid>
            <pubDate>Thu, 15 Aug 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[I decided to write down all the advice on website building that I always give my friends and customers so that I don't ever miss anything out. This is the first of several articles.]]></description>
            <content:encoded><![CDATA[<figure><img src="https://www.cheehow.dev/assets/images/freestocks-org-I_pOqP6kCOI-unsplash-637a5927d6b6100b7d2d36bd79a84b38.jpg" alt="hands typing on a laptop with another laptop by the side"><figcaption>Photo by <a target="_blank" href="https://unsplash.com/@freestocks">freestocks.org</a> on <a target="_blank" href="https://unsplash.com/search/photos/website">Unsplash</a></figcaption></figure>
<p>I decided to write down all the advice on website building that I always give my friends and customers so that I don't ever miss anything out. This is the first of several articles.</p>
<p>I've been making webpages since the 90s. So I think I know a thing or two about building websites.</p>
<p>I really ought to since I've already built more than a handful of websites professionally and for my business owner friends.</p>
<p>Every time I do so, I find that I have to explain the same things to my clients and friends—the things to watch out for, the parts that make up the website, the available kinds of hosting options, etc.</p>
<p>The thing is, there are so many things to mention that each time I explain, I inevitably miss something out. So I decided to write it all down in the form of articles, listicles, or checklists that are easy to read and digest. My target readers are the average people and small business owners. I try to be as concise and non-technical as possible, so that they can read, understand, do it right, and get on with their lives.</p>
<p>To keep the length of this article manageable, I will discuss just the three fundamental things to look out for.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="1-make-sure-domain-ownership-is-clear">1. Make Sure Domain Ownership is Clear<a href="https://www.cheehow.dev/blog/2019/08/15/3-things-to-watch-out-for-when-commissioning-your-website#1-make-sure-domain-ownership-is-clear" class="hash-link" aria-label="Direct link to 1. Make Sure Domain Ownership is Clear" title="Direct link to 1. Make Sure Domain Ownership is Clear">​</a></h2>
<p>If there is only one thing I can share, it is this: make sure you own the domain!</p>
<p>"Why would I not own the domain? I paid for it!"</p>
<p>That's the typical response I get. The reason is that domain names are registered with <a href="https://www.icann.org/" title="Internet Corporation for Assigned Names and Numbers">ICANN</a> through registrars. When a domain name is registered, there are 4 pieces of contact information that needs to be provided—registrant, admin, tech, and billing.</p>
<p>Most important among them is the registrant information—the entity/person that has registered for the domain.</p>
<p>So why would that be a problem? The issue is actually due to human behaviour. You see, people loathe to enter data into fields. The cognitive burden when entering fields for four contacts is even higher. As a result, many vendors are often tempted to enter one set of information (his/her own) and use the same for all four contacts (this is usually made possible by the user interface).</p>
<p>Most of the time, this is not a problem, but when it does become a problem, there is generally no recourse for the site owner. The problem typically manifests itself when the working relationship between the vendor and the site owner turns sour.</p>
<p>I have not had to deal with this yet, fortunately. But imagine if the vendor became hostile and denies the domain to you, the site owner, there would be no records of ownership as far as ICANN is concerned. If the vendor is not cooperative, it would take you a king's ransom and a long time in order to reclaim the domain.</p>
<p>This is why it is so, so important for you to make sure that the selected vendor is a reliable and trustworthy one. Otherwise, it might be better to just handle the domain portion personally.</p>
<p>I will be writing a <a href="https://www.cheehow.dev/blog/2019/08/26/about-domain-names/">piece on domain names separately</a> to delve into more details.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="2-costs-are-not-necessarily-indicative-of-quality">2. Costs Are Not Necessarily Indicative of Quality<a href="https://www.cheehow.dev/blog/2019/08/15/3-things-to-watch-out-for-when-commissioning-your-website#2-costs-are-not-necessarily-indicative-of-quality" class="hash-link" aria-label="Direct link to 2. Costs Are Not Necessarily Indicative of Quality" title="Direct link to 2. Costs Are Not Necessarily Indicative of Quality">​</a></h2>
<p>Creating a website is not like buying a car where there are clear boundaries that links quality with the right price tag.</p>
<p>Two vendors (developers) can quote the same price for a website but deliver wildly different results.</p>
<p>In my next piece on website fundamentals, I discuss the dirty little secrets of the industry (among other reasons) that explain why there is now such a large variation of quality.</p>
<p>So if price is not the answer, then what is?</p>
<p>There are generally two ways to make sure you hire the right developer.</p>
<p>One, check out the developer's previous work. For most of you reading this, the only criterion by which the work can be judged is through the aesthetics. That is well and good, but may not be sufficient, as I'll explain in another article.</p>
<p>Two, have the developer create the mock-up (also sometimes referred to as the prototype) of the website before starting actual programming work. This way you can have an idea of what the final product will look like much more quickly (and cheaply) than waiting for the site to be fully developed. This is the way it is because it takes a lot more work and time to create the actual website than to illustrate what the final design will look like.</p>
<p>To make it fair for both parties, I always recommend creating the mock-up first. Let's be clear, the mock-up isn't some sketch or hand-drawn representation of the site. Rather, it is an almost exact replica of the website. There are tools now that do not even cost money that the vendor can use to present the final look-and-feel without writing a single line of code.</p>
<p>I also recommend that you pay a fair sum of money for this prototype. While no code is written, it still takes time, effort and creative brain juice to think of and create the design. There is no right figure as the price of a website may differ greatly. Generally though, some 10% to 25% may be a ballpark figure to pay for this mock-up. It is a good way to hedge the risk and still be fair to both you and the vendor.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="3-check-the-email-service-provider">3. Check the Email Service Provider<a href="https://www.cheehow.dev/blog/2019/08/15/3-things-to-watch-out-for-when-commissioning-your-website#3-check-the-email-service-provider" class="hash-link" aria-label="Direct link to 3. Check the Email Service Provider" title="Direct link to 3. Check the Email Service Provider">​</a></h2>
<p>From my experience, when a business owner wants to create his or her own website, that usually means there is no decent email service as well.</p>
<p>By "decent" I mean an email address ending in the same domain as your website. That means no @singnet.com.sg, @gmail.com, or @outlook.com addresses.</p>
<p>This is another topic that warrants another article. For now just be aware that there are many email server options that may be close in price but vary greatly in terms of features and functions.</p>
<p>I think that Gmail has set the gold standard for email service. To me, an inbox capacity of less than a gigabyte is not considered usable given the propensity for people to send large attachments nowadays.</p>
<p>Yet, there are still traditional providers that provide (understandably small capacity) email accounts along with web hosting as a package on the cheap. While that might sound nice, especially for the start where you think "I can just change when my business grows", the reality is typically different.</p>
<p>Email is a critical business function in the work environment. When you start outgrowing your meagre inbox capacity, you'll start to experience all the inefficiencies and potential lost businesses due to a full inbox.</p>
<p>If you then want to switch to a bigger inbox, and you wish to move the contents from the old inbox to the new one, there is then this email migration cost that you will have to factor in. This migration cost is significantly higher than the subscription price of your email service. Unless… you are alright with putting up with the inconvenience of switching between your old inbox and the new one (and potential confusion that comes with it).</p>
<p>Bear in mind that this does not affect just yourself but the other coworkers in your company that have an inbox. So any inefficiency/lost productivity is magnified.</p>
<p>In summary, if you want to avoid this kind of headaches and potential lost productivity, be sure to get your email hosting solution right at the start.</p>
<p>(If you want to have the Gmail equivalent experience for your inbox, use <a href="https://gsuite.google.com/" target="_blank" rel="noopener noreferrer">G Suite</a>! If you decide to go with that, <a href="https://twitter.com/chuacheehow" target="_blank" rel="noopener noreferrer">hit me up</a>! I've got promotion codes for you that give you 20% off the first year subscription per user. Also, I get a commission 😉)</p>
<p>So that's it. These are the three things that I would advise anyone thinking of commissioning a website to establish a web presence. Reach me on Twitter (<a href="https://twitter.com/chuacheehow" target="_blank" rel="noopener noreferrer">@chuacheehow</a>) if you have any questions.</p>
<p>(Also posted on <a href="https://medium.com/@cheehow_c/3-things-to-watch-out-for-when-commissioning-your-website-d93a6706c8f6?source=friends_link&amp;sk=c40b6cbc074bd9249bf6ef924852446c" target="_blank" rel="noopener noreferrer">Medium</a> and <a href="https://www.linkedin.com/pulse/3-things-watch-out-when-commissioning-your-website-chee-how-chua" target="_blank" rel="noopener noreferrer">LinkedIn</a>.)</p>
<p>My thanks go to <a href="https://www.facebook.com/jabmimi" target="_blank" rel="noopener noreferrer">Abdul Rahman</a> for helping with proofreading.</p>]]></content:encoded>
            <category>websitetips</category>
            <category>domains</category>
            <category>emailservicetips</category>
            <category>sme</category>
            <category>smallbusiness</category>
        </item>
        <item>
            <title><![CDATA[Leaving My Company]]></title>
            <link>https://www.cheehow.dev/blog/2019/02/01/leaving-my-company</link>
            <guid>https://www.cheehow.dev/blog/2019/02/01/leaving-my-company</guid>
            <pubDate>Fri, 01 Feb 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Two months ago I left the company which I co-founded 13 years back. Here are some of my takeaways after 13 years as its CTO.]]></description>
            <content:encoded><![CDATA[<figure><img src="https://www.cheehow.dev/assets/images/hero-c0b1f0a6f3c851d55aecc606bf22ba98.jpg" alt="photo of a balloon in Orchard Road, Singapore"><figcaption>Photo credit: Chua Chee How</figcaption></figure>
<p>Two months ago I left the company which I co-founded 13 years back. Here are some of my takeaways after 13 years as its CTO.</p>
<p>But first, an introduction.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="back-story">Back story<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company#back-story" class="hash-link" aria-label="Direct link to Back story" title="Direct link to Back story">​</a></h2>
<p>We are a company focused on education technologies that improve the pedagogical aspects of learning in schools.</p>
<p>Throughout our 13 years of operation, we've taken on work and projects of different scopes. We started with software training for adults. Back then Photoshop and its ilk from Adobe, and Dreamweaver and the Macromedia suite of applications were the must-knows for image manipulation and Web development.</p>
<p>Business was slow. A year or two after we started, we reached an inflection point. We had to decide to wind up or to pivot to a different business scope. Being the young and full-spirited youngsters we were, we wanted to give entrepreneurship another shot before throwing in the towel. With a stroke of luck, through the relationship that one of the founders had with people from Novell, we got on board a programme to supply training services to public schools.</p>
<p>Back then, there was a strong emphasis on graphical programs and interactive multimedia as a result of the Ministry of Education (MOE) IT Master Plan. With the fortuitous early investment (of time) I made into learning the Adobe and Macromedia suite of programs (think Photoshop, Flash, Dreamweaver and the likes), I was able to conduct the courses that we pitched to the schools.</p>
<p>Thanks to our partnership with Novell, we were able to gain some traction with school trainings. As Novell had acquired SUSE Linux not too long back, we also had the privilege of introducing Linux to schools. It was also then that I really sunk my teeth into Linux. (Since then, I've switched to using Linux on the desktop exclusively. I'm very thankful for that chance to really learn Linux well.)</p>
<p>The margins from training were already slim back then. Competition was intense, coming from one-person shops to existing incumbents. We thus had to be opportunistic, grabbing all kinds of deals that came our way. Along the way, through Novell and other channels, we also got a few deals that involved server deployment - completely unrelated to education.</p>
<p>As the sole technical founder, I had to equip myself with knowledge of Linux server deployment to perform the actual deployment while also conducting trainings in schools.</p>
<p>When it comes to the choice of projects, we were really not discerning, all in the name of survival. In 2006 (I think), we even clinched the deal for technical support for the Nokia phones distributed to the attendees of the International Monetary Fund (IMF) conference in Singapore.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="google">Google<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company#google" class="hash-link" aria-label="Direct link to Google" title="Direct link to Google">​</a></h2>
<p>Sometime between 2006 and 2008, we had our first contact with Google. At that time, they were located at Shenton Way where they took up an entire floor (or was it two?) in AXA Tower.</p>
<p>It was also then when we were introduced to what is now known as G Suite. We were early to the party. Being education focused, we were the first to introduce Google Apps, as it was then called, to schools.</p>
<p>We also became a reseller, selling Google Apps to commercial entities (the education edition is free of charge to educational institutes).</p>
<p>That went on for a while until we also became a Chrome Device Management license reseller with our own brand of Chromebooks.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="applications">Applications<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company#applications" class="hash-link" aria-label="Direct link to Applications" title="Direct link to Applications">​</a></h2>
<p>Along the journey, we also created a plethora of applications:</p>
<ul>
<li><a href="http://chromeclass.com/" target="_blank" rel="noopener noreferrer">Chromeclass</a> (software to manage student Chromebooks),</li>
<li><a href="http://woma.jotterlab.com/" target="_blank" rel="noopener noreferrer">Woma</a> (workload management tool for Google Classroom),</li>
<li><a href="https://webnap-gsa.appspot.com/" target="_blank" rel="noopener noreferrer">WebNap</a> (cyber safety testing tool),</li>
<li>Jotterlab (this name was used for different projects as we groomed and killed a few initiatives along the way),</li>
<li>VLS (stands for Virtual Lab for Science),</li>
<li><a href="https://trustednetworkext.appspot.com/" target="_blank" rel="noopener noreferrer">Trusted Network Extension</a> (an IP tracking tool),</li>
<li><a href="https://g-flip.appspot.com/" target="_blank" rel="noopener noreferrer">GFlip</a> (video repository for flipped learning),</li>
<li>Ductbooks (a book delivery and management system),</li>
<li>Edurious (a component of an learning management platform for low bandwidth environments), and</li>
<li>Locus (a shared access terminal for Chromebooks with more controls than a Chromebook in Public Terminal mode).</li>
</ul>
<p>Among these, a third of them were just proof-of-concept. One third of these is still being used by customers. The remaining are in the trash.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="unified-vision">Unified vision<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company#unified-vision" class="hash-link" aria-label="Direct link to Unified vision" title="Direct link to Unified vision">​</a></h2>
<p>So that was the story for 13 years in a nutshell. When we started, there were four shareholders. When I left, there were only two key decision makers, including myself.</p>
<p>Probably as a result of having only two decision makers, some of my realisations were more palpable than others.</p>
<p><em>In order for a company to move as a whole, there must be a clear direction to move towards. In corporate speak, this is the company vision and mission.</em></p>
<p>If there is no consensus as to what the company vision and mission are, then the baseline mission is profit maximisation. The organization then behaves like an indiscriminate eater, gobbling up every piece of morsel that comes its way, regardless if it's toxic or nutritious.</p>
<p>In some cases, a one-off project with seemingly low returns, if any at all, may be necessary as part of an overarching strategy, to augment the company's position in the market. These projects are necessary evils, medicine that the company must take to further its business interests.</p>
<p>In other cases, such one-off projects with seemingly high (potential) returns may feel like the sweet flesh of low lying fruits but they draw the company's resources away from its core focus. In the best case, they are profitable distractions. In the worst case(s), they are loss-making adventures that hold the company back.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="gauging-product-market-fit">Gauging product market fit<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company#gauging-product-market-fit" class="hash-link" aria-label="Direct link to Gauging product market fit" title="Direct link to Gauging product market fit">​</a></h2>
<p><em>Before committing to making a product, make sure that a good part of the market wants it.</em></p>
<p>We made the critical mistake of “surveying a market of one”. We didn't do enough market research to identify the market demand for the Web app we were planning to make.</p>
<p>Just because we hear the need from one or two potential customers, it does not mean there is a market demand for a solution. This statement sounds so obvious that it is almost redundant to state it. The problem is that we often fall to the trap of hearing only what we want to hear. When the person at the other end is in 100% consensus with you, it can feel like the whole world is in agreement.</p>
<p>One trick to identify this kind of conversation is when the person makes sweeping statements like “Oh, everyone will need this solution.” It is not so much the accuracy or correctness of the statement (because who knows for sure?) that is the problem but rather that such statements lull the subconscious into thinking that they are facts rather than opinions or guesses.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ease-of-use-trumps-value-proposition">Ease of use trumps value proposition<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company#ease-of-use-trumps-value-proposition" class="hash-link" aria-label="Direct link to Ease of use trumps value proposition" title="Direct link to Ease of use trumps value proposition">​</a></h2>
<p><em>The value proposition provided by an application must be a magnitude greater than the effort to achieve it.</em></p>
<p>I learnt this lesson from the same failed project that showed the importance of market demand.</p>
<p>The software was to help students become better essay writers by making incremental improvements to their essays through a methodology called “process writing”. With this methodology, students write several versions of an essay. Their peers and teachers can the review the essay and make comments on areas that need improving.</p>
<p>This all sounds good.</p>
<p>The problem is that we did not realise the amount of work required in this process, for both the students and teachers. From the perspective of students, writing just one essay is already a lot of work. To have them write the same essay more than once, in addition to their other assignments, is a tall order. Ditto for the teachers, whose workload is already too much. There is little to no incentive to use such an application.</p>
<p>Despite the premise of the program, it was simply too much additional work for the users. The project was doomed to fail at conception.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-it-takes-to-make-good-software">What it takes to make good software<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company#what-it-takes-to-make-good-software" class="hash-link" aria-label="Direct link to What it takes to make good software" title="Direct link to What it takes to make good software">​</a></h2>
<p><em>Being able to rapidly prototype an application to validate an idea does not mean it is trivial to write good software.</em></p>
<p>Very often, in the quest for rapid development, developers have to take shortcuts. Such shortcuts may meet the project's current and immediate goals but are typically detrimental to its future development. Such shortcuts are known as technical debt.</p>
<p>Like financial debt, the more you take on, the deeper you sink. Without understanding this, it is <em>so</em> easy to fall into the trap of thinking that a software project is done once all the checkboxes are ticked.</p>
<p>Feedback loop with early customers has to be proactive and regular. A software product is almost always never done. There are always features to add, and bugs to fix.</p>
<p>The people who put money with you before you have any traction is trusting you with their money. There is a moral imperative to reciprocate that trust by making the product/service the best that it can be. If, however, you need to keep getting different projects then either a) the model of creating your own software is not tenable, or b) the project is not something that the market needs i.e. the project should not exist, and should be trimmed to make space for (allocate resources to) other projects that might have a better chance of succeeding in the market.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="in-conclusion">In conclusion<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company#in-conclusion" class="hash-link" aria-label="Direct link to In conclusion" title="Direct link to In conclusion">​</a></h2>
<p>The company is now, and has been for a few years, stable and growing the Chrome business. We would not have imagined the hardware business making up the main chunk of the revenue, and yet, the company now stands as the Singapore's leading company for G Suite and Chrome technology in the education sector. With any luck, the company may still soar to greater heights in the right direction and focus. I wish for only the best to the company and my former colleagues.</p>
<p>(Also posted on <a href="https://medium.com/@cheehow_c/leaving-my-company-a2d25f5051b9" target="_blank" rel="noopener noreferrer">Medium</a> and <a href="https://www.linkedin.com/pulse/leaving-my-company-chee-how-chua/" target="_blank" rel="noopener noreferrer">LinkedIn</a>.)</p>]]></content:encoded>
            <category>reflection</category>
            <category>personal</category>
        </item>
        <item>
            <title><![CDATA[Effective Presentations - Part 2 of 2]]></title>
            <link>https://www.cheehow.dev/blog/2017/02/24/effective-presentations-part-2-of-2</link>
            <guid>https://www.cheehow.dev/blog/2017/02/24/effective-presentations-part-2-of-2</guid>
            <pubDate>Fri, 24 Feb 2017 00:00:00 GMT</pubDate>
            <description><![CDATA[In the previous article, I wrote about my attempt at improving my pitches. I left off from that piece with the promise of a formula that can improve the quality of your slide decks immediately.]]></description>
            <content:encoded><![CDATA[<figure><img src="https://www.cheehow.dev/assets/images/aaron-burden-90144-40faa49baf19b304fe76a76379dc5f26.jpg" alt=""><figcaption>Photo credit: <a href="https://unsplash.com/photos/CKlHKtCJZKk" target="_blank">Unsplash</a></figcaption></figure>
<p>In the <a href="https://www.cheehow.dev/blog/2017/02/06/effective-presentations-part-1-of-2/">previous article</a>, I wrote about my attempt at improving my
pitches. I left off from that piece with the promise of a formula that can
improve the quality of your slide decks immediately.</p>
<p>The answer: <em>storytelling</em>.</p>
<p>The problem with this statement is it seems too simple, even patronizing, an
answer.</p>
<p>From another perspective, it could be that because the answer is so simple, it
is easy to dismiss.</p>
<p>But if you can take a moment to digest this answer, you will begin to realise
that it makes sense. Notice that in any TV series, every episode tries to end
with a cliffhanger. Producers do that because they know that it makes the
audience look forward to watching the next episode to find out what happens
next, that they want to “fill in the gap” in the whole story.</p>
<p>Storytelling is a process from the start to the end. Anything missing in this
process is a gap. No one likes gaps. Everyone wants closure. That’s why it is
more painful to lose a loved one suddenly because we lose the chance to say
our last words - closure.</p>
<p>Every Hollywood movie nowadays have equally stunning visual effects but what
makes one movie A-grade and another subpar is really the quality of the story,
an element that is not as much observed as it is felt.</p>
<p>“If storytelling is the answer, then what is the formula?” I can already
imagine this question surfacing in your mind as you read this.</p>
<p>The answer can be found from this <a href="https://medium.com/firm-narrative/want-a-better-pitch-watch-this-328b95c2fd0b#.wrn0fp5ad" target="_blank" rel="noopener noreferrer">Medium piece</a> by <a href="https://medium.com/@raskin" target="_blank" rel="noopener noreferrer">Andy Raskin</a>.</p>
<p>I replicate below the points which he made in that article:</p>
<blockquote>
<ol>
<li>Name the enemy</li>
<li>Answer “Why now?”</li>
<li>Show the promised land before explaining how you’ll get there</li>
<li>Identify obstacles—then explain how you’ll overcome them</li>
<li>Present evidence that you’re not just blowing hot air</li>
</ol>
</blockquote>
<p>If you are really interested in brushing up your presentations, go read that
piece. It’s only a 5-minute read.</p>
<p>I also like to share this <a href="https://www.youtube.com/watch?v=5pFI9UuC_fc&amp;t=2s" target="_blank" rel="noopener noreferrer">video series</a> on YouTube featuring Ira Glass
from <a href="https://www.thisamericanlife.org/podcast" target="_blank" rel="noopener noreferrer">This American Life</a> where he talks about creating compelling
storylines using anecdotes and a series of actions and questions.</p>
<p>I’m certainly no presentation expert (far from it), but by just applying what
I’ve learnt from the Raskin article and Glass videos, I do think that my works
have improved from what they were before.</p>
<p>I hope they will do the same for you. Share your thoughts with me in the
comments below or on Twitter <a href="https://twitter.com/chuacheehow" target="_blank" rel="noopener noreferrer">@chuacheehow</a></p>
<p>(Also posted on
<a href="http://medium.com/@cheehow_c/effective-presentations-part-2-of-2-8f212fae17a7" target="_blank" rel="noopener noreferrer">Medium</a>
and <a href="https://www.linkedin.com/pulse/effective-presentations-part-2-chee-how-chua" target="_blank" rel="noopener noreferrer">LinkedIn</a>)</p>]]></content:encoded>
            <category>presentation</category>
            <category>public speaking</category>
        </item>
        <item>
            <title><![CDATA[Effective Presentations - Part 1 of 2]]></title>
            <link>https://www.cheehow.dev/blog/2017/02/06/effective-presentations-part-1-of-2</link>
            <guid>https://www.cheehow.dev/blog/2017/02/06/effective-presentations-part-1-of-2</guid>
            <pubDate>Mon, 06 Feb 2017 00:00:00 GMT</pubDate>
            <description><![CDATA[I’m always looking for ways to improve my presentations. Oftentimes, I only get one chance to get my point across and I want to make every such opportunity count.]]></description>
            <content:encoded><![CDATA[<figure><img src="https://www.cheehow.dev/assets/images/kx4mm3znzbc-chuttersnap-55f6b354f9dd3e9d7a8608e67014e9db.jpg" alt=""><figcaption>Photo credit: <a href="https://unsplash.com/photos/Kx4Mm3ZnZBc" target="_blank">Unsplash</a></figcaption></figure>
<p>I’m always looking for ways to improve my presentations. Oftentimes, I only
get one chance to get my point across and I want to make every such
opportunity count.</p>
<p>I had once thought that the key to well done presentations is a slick,
animated slideshow with concise key points. Now I know better. What you use
as the visual material is secondary to <em>what you are saying</em> and <em>how you say
it</em>.</p>
<p>I would attribute the “how you say it” to the command and fluency of the
language that you are presenting in. This has to do with the richness of your
vocabulary and the structure of the sentences that you articulate during the
presentation. Your language skills, like any other skills, can only be
improved through repeated practice. So there’s that.</p>
<p>“What you say” though are the contents of your presentation. Some might argue
that how you say it is more important then what you say. That argument, I
think, is probably only true for the very few speakers who seem to naturally
exude such charisma that can charm the masses. Needless to say, that is
certainly not an attribute that the large majority of us can emulate.</p>
<p>Contents, however, are highly malleable. They are the one thing in the
presentation that you can change with ease. What is not as easy is to know
<em>what</em> to change it to.</p>
<p>We all want an easy-to-apply formula that we can use on our presentation decks
right now while we polish up our language skills and vocabulary gradually.
But does such a formula exist? If so, it sounds too good to be true, isn’t
it?</p>
<p>What if there is such a thing? And that it is the same formula that
differentiates an A-grade movie from a B-grade one.</p>
<p>If you feel that all the presentations that you have ever done in your life
are, how should I say, <em>lacklustre</em>, then you can probably see a great
improvement in your slide decks simply by applying this formula. I know that
it works for me.</p>
<p>Like any good show, I am going to leave this post on a cliff-hanger and come
back with the second and final part of this article next time.</p>
<p>(Also posted on
<a href="https://medium.com/@cheehow_c/effective-presentations-part-1-of-2-962b1b421a1c#.bvuvu4nva" target="_blank" rel="noopener noreferrer">Medium</a>
and <a href="https://www.linkedin.com/pulse/effective-presentations-part-1-2-chee-how-chua" target="_blank" rel="noopener noreferrer">LinkedIn</a>)</p>]]></content:encoded>
            <category>presentation</category>
            <category>public speaking</category>
        </item>
        <item>
            <title><![CDATA[A Lesson from Twitter]]></title>
            <link>https://www.cheehow.dev/blog/2016/12/21/a-lesson-from-twitter</link>
            <guid>https://www.cheehow.dev/blog/2016/12/21/a-lesson-from-twitter</guid>
            <pubDate>Wed, 21 Dec 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[<img src=]]></description>
            <content:encoded><![CDATA[<figure><img src="https://www.cheehow.dev/assets/images/haipj8pyel8-freestocks-org-a94a3297d2e615ab7a6c7d534720aedc.jpg" alt=""><figcaption>Photo credit: <a href="https://unsplash.com/photos/HAIPJ8PyeL8" target="_blank"></a><a href="https://unsplash.com/photos/HAIPJ8PyeL8" target="_blank" rel="noopener noreferrer">https://unsplash.com/photos/HAIPJ8PyeL8</a></figcaption></figure>
<p>Several months back I was addicted to Twitter. Any time I can pull out my
phone, I would be checking my Twitter feed.</p>
<p>It's a time waster. Prolific YouTuber <a href="https://en.wikipedia.org/wiki/Derek_Muller">Dr Derek Muller</a>
describes it as a part of the <a href="https://www.youtube.com/watch?v=iYYuiWP0IpA">distraction economy</a>.</p>
<p>I had even gone to the extent of checking for more updates when I had finished
everything in my feed. What was the use of that? Is there anything to gain
from all that time spent reading little messages from strangers?</p>
<p>Given that each message is at most 140 characters, surely Twitter's only value
is for newsy stuff right? Well, that's mostly true but every now and then, you
can find a gem of wisdom among the stream of ramblings.</p>
<p>And found one I did. I don't remember the exact wording but the gist revolves
around these two sentences:</p>
<blockquote>
<p>"Why is this job important?"</p>
<p>"What you will learn in this job."</p>
</blockquote>
<p>This was posted by someone who was in the position of hiring (programmers I
think). He found that by including these two points in a job advertisement, it
helped to attract more quality candidates than not.</p>
<p>After parsing through the sentences, I can see why. The first point "What is
this job important?" probably does not make sense to a lot of people why it
would help. The second point "What you will learn in this job." is probably
more obvious. Clearly it speaks to people who want to learn more. Beyond that
though, if we delve a little deeper into the characteristics of the people who
place emphasis on it, we can easily see that these are people who want and
desire to acquire new knowledge.</p>
<p>Naturally, if I were to infer another characteristic that makes such a person
perpetually curious, it would be interest, or for some, passion. Only when you
have interest/passion in a job, would you be always keen to learn more. And a
person who is interested/passionate can be counted on to complete the tasks
satisfactorily, not necessarily to the supervisor but simply to herself.</p>
<p>What about the first point? What can we infer from it?</p>
<p>A disassociated worker likely doesn't give a damn about why the job is
important. I can think of two traits in an individual who <em>does</em> give a damn.</p>
<p>One is the ability to think at a higher level, "see the big picture", and
understand and appreciate the role that she is playing in the organization for
the job that she is doing.</p>
<p>The other is an innate desire for self actualization. For some people, the
knowledge that one has a significant role to play in the company provides the
extra motivation to work hard. I think that's probably the reason why some
people stay behind after office hours to complete the task at hand
whereas others adopt a "couldn't care less" attitude in the office.</p>
<p>Simply adding these two points in the job advertisement will not magically
filter out the dispassionate candidates, but you can leverage these two points
during the interview to "suss" out these hidden personality traits in the
candidates.</p>
<p>If you are in a position of hiring, try this out the next time a position is
available and see if it works for you.</p>]]></content:encoded>
            <category>twitter</category>
            <category>hiring</category>
        </item>
        <item>
            <title><![CDATA[A little lesson on binding]]></title>
            <link>https://www.cheehow.dev/blog/2016/09/28/a-little-lesson-on-binding</link>
            <guid>https://www.cheehow.dev/blog/2016/09/28/a-little-lesson-on-binding</guid>
            <pubDate>Wed, 28 Sep 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[I've been writing JavaScript for the past 10 years for my work, and there are]]></description>
            <content:encoded><![CDATA[<p>I've been writing JavaScript for the past 10 years for my work, and there are
still things in the language that trips me up. A very good example is on binding.</p>
<p>Given the setup below, I would have been a <em>little</em> hesitant as to what the
right answer is.</p>
<div class="language-JavaScript language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Alpha</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'A'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Alpha</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method-variable function-variable method function property-access" style="color:#d73a49">say</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Beta</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'B'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Beta</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method-variable function-variable method function property-access" style="color:#d73a49">say</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'G'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">echo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">action</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">action</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Alpha</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Beta</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// returns A</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// returns B</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// returns G</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Nothing fancy up to this point. But the next 2 lines will make me think a bit.</p>
<div class="language-JavaScript language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">echo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">say</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Output: 'G'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">echo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">bind</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Output: 'A'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This next part is the kicker.</p>
<div class="language-JavaScript language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Delta</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'D'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">say</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">bind</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Delta</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method-variable function-variable method function property-access" style="color:#d73a49">say</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">d </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Delta</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">d</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">echo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">d</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">say</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>What do you think the output is?</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="answer">ANSWER<a href="https://www.cheehow.dev/blog/2016/09/28/a-little-lesson-on-binding#answer" class="hash-link" aria-label="Direct link to ANSWER" title="Direct link to ANSWER">​</a></h3>
<p>Both lines output "D".</p>
<p>This example shows that there is a case for early binding even on prototype
methods.</p>]]></content:encoded>
            <category>basics</category>
            <category>javascript</category>
            <category>programming</category>
            <category>binding</category>
        </item>
        <item>
            <title><![CDATA[LG has won me over]]></title>
            <link>https://www.cheehow.dev/blog/2016/09/15/lg-has-won-me-over</link>
            <guid>https://www.cheehow.dev/blog/2016/09/15/lg-has-won-me-over</guid>
            <pubDate>Thu, 15 Sep 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[About a year ago, I bought my wife and I a new phone for each of us. For her]]></description>
            <content:encoded><![CDATA[<p>About a year ago, I bought my wife and I a new phone for each of us. For her
it was a Galaxy Note 5. For me, I got a LG G4.</p>
<p>At that point in time, the G4 was considered slightly below par compared to
the Note 5, in terms of price and branding. I had aimed for a V10 but there
was completely no news about it being available in Singapore.</p>
<p>Despite being a flagship phone for Samsung, there were plenty of reasons for
not choosing the Note 5 then - the <a href="https://www.google.com.sg/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=6&amp;cad=rja&amp;uact=8&amp;ved=0ahUKEwjj5eXgwJHPAhVGoJQKHT-qCO8QFgg6MAU&amp;url=http%3A%2F%2Fwww.theverge.com%2F2016%2F1%2F19%2F10789208%2Fsamsung-note-5-stylus-fix&amp;usg=AFQjCNE79xIR20GNeloNmKXj8cAM7XA1ww" target="_blank" rel="noopener noreferrer">stylus
problem</a>,
the non-removable battery and the lack of external storage. I had no regrets
not selecting the Note 5.</p>
<p>Notwithstanding all the shortcomings, I had a more pragmatic reason for
choosing the G4 over the Note 5 though - price. To me, it was that I did not
think that the Note 5 was worth the extra money over the G4; all the features
that the phone touted (and the Samsung branding) were not worth the premium
over the G4.</p>
<p>Now, my stance is more opinionated - I think the support for LG is simply
better than the Samsung. In the time between my wife getting her Note 5 to her
first OS upgrade from Android 5.1 to Android 6, I had already gotten three
updates. My G4 was revved up to Android M months before her Note 5 was
upgraded. My G4 also got another update recently, though I'm not sure what the
upgrade was - my assumption is that it is for some security patches.</p>
<p>Regardless of the reason for the latest update, the fact that LG has provided
more frequent updates than Samsung has (for its flagship phone no less) is
enough reason for me to not choose Samsung phones again.</p>
<p>P.S. I had <em>begun</em> writing this article before the <a href="https://www.google.com.sg/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;cad=rja&amp;uact=8&amp;ved=0ahUKEwjova-VwpHPAhUFlZQKHUhOBlQQqQIIHTAA&amp;url=https%3A%2F%2Fwww.cnet.com%2Fnews%2Fwhy-is-samsung-galaxy-note-7-exploding-overheating%2F&amp;usg=AFQjCNHlQSxAuGD-5Kb_oAKwAAZECOsS2g" target="_blank" rel="noopener noreferrer">Note 7 battery
problems</a>
surfaced so the battery problem wasn't the genesis for my opinion.</p>]]></content:encoded>
            <category>android</category>
            <category>lg</category>
            <category>samsung</category>
            <category>g4</category>
            <category>note5</category>
        </item>
        <item>
            <title><![CDATA[Installing Disqus]]></title>
            <link>https://www.cheehow.dev/blog/2016/07/19/installing-disqus</link>
            <guid>https://www.cheehow.dev/blog/2016/07/19/installing-disqus</guid>
            <pubDate>Tue, 19 Jul 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[So I've gotten around to installing Disqus for this blog. This post is just a]]></description>
            <content:encoded><![CDATA[<p>So I've gotten around to installing Disqus for this blog. This post is just a
test post for testing the commenting system.</p>
<p>(2023 February note: Disqus was not enabled after the switch to <a href="https://docusaurus.io/" target="_blank" rel="noopener noreferrer">Docusaurus</a>)</p>]]></content:encoded>
            <category>disqus</category>
        </item>
        <item>
            <title><![CDATA[Patching with GIF DIFF]]></title>
            <link>https://www.cheehow.dev/blog/2016/04/04/patching-with-git-diff</link>
            <guid>https://www.cheehow.dev/blog/2016/04/04/patching-with-git-diff</guid>
            <pubDate>Mon, 04 Apr 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[I've recently had the opportunity to work with some remote teams to]]></description>
            <content:encoded><![CDATA[<p>I've recently had the opportunity to work with some remote teams to
collaborate on a project. One question that cropped up was how do I
pass the project specific changes to the remote team members without
committing the credentials to the repository.</p>
<p>The easiest way that I thought of was to create a DIFF file and pass
the file to the other members so that they could patch the project
prior to deployment to production servers.</p>
<p>The most straightforward way to create a DIFF file is to use <code>git diff</code>. But the question was how can the DIFF file be used to "patch" the project?</p>
<p>Thanks to the (blog post from Thomas Amsler)[<a href="http://tamsler.blogspot.sg/2009/02/patching-with-git-diff.html" target="_blank" rel="noopener noreferrer">http://tamsler.blogspot.sg/2009/02/patching-with-git-diff.html</a>],<!-- --> this is easily achieved.</p>
<p>First, create the patch file like so:</p>
<p>git diff --no-prefix &gt; patchfile</p>
<p>This file can then be used as a patch like so:</p>
<p>patch -p0 &lt; patchfile</p>
<p>If the patch was created without <code>--no-prefix</code>, the patch level
should be 1 instead:</p>
<p>git diff &gt; patchfile
patch -p1 &lt; patchfile</p>]]></content:encoded>
            <category>git</category>
            <category>diff</category>
            <category>patch</category>
            <category>programming</category>
        </item>
        <item>
            <title><![CDATA[Running SWF Files]]></title>
            <link>https://www.cheehow.dev/blog/2016/02/24/running-swf-files</link>
            <guid>https://www.cheehow.dev/blog/2016/02/24/running-swf-files</guid>
            <pubDate>Wed, 24 Feb 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[I was recently posed with a question on how to run Adobe Flash files]]></description>
            <content:encoded><![CDATA[<p>I was recently posed with a question on how to run Adobe Flash files
in the browser. As far as I know, you can write a simple HTML page
to embed the Flash file (<code>SWF</code>) in a page and load in the
browser (<a href="http://superuser.com/questions/116352/how-can-i-play-an-swf-file-using-google-chrome"></a><a href="http://superuser.com/questions/116352/how-can-i-play-an-swf-file-using-google-chrome" target="_blank" rel="noopener noreferrer">http://superuser.com/questions/116352/how-can-i-play-an-swf-file-using-google-chrome</a>).
I also recall that any decent browser would be able to load the SWF
file as-is without having to do anything extra.</p>
<p>However, loading the SWF file in Chrome on Linux does not work;
loading the file causes Chrome to prompt the user to download it -
definitely not the reaction I was hoping from the browser. Trying to
solve this problem lead to learn a new thing about MIME types in Linux.</p>
<p>From <a href="http://superuser.com/questions/726789/flash-files-swf-prompts-for-download-instead-of-opening/783451#783451">superuser.com</a>,
I learnt that file associations are placed in the file</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">/usr/share/mime/packages/freedesktop.org.xml</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>and that the default MIME type for <code>swf</code> is</p>
<div class="language-xml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-xml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">mime-type</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">application/vnd.adobe.flash.movie</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>To make the SWF file play in the browser, change the MIME type to</p>
<div class="language-xml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-xml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">mime-type</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">application/x-shockwave-flash</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>and then update the association by running</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">update-mime-database /usr/share/mime</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>]]></content:encoded>
            <category>flash</category>
            <category>swf</category>
        </item>
        <item>
            <title><![CDATA[More tips for BackboneJS]]></title>
            <link>https://www.cheehow.dev/blog/2016/02/19/more-tips-for-backbonejs</link>
            <guid>https://www.cheehow.dev/blog/2016/02/19/more-tips-for-backbonejs</guid>
            <pubDate>Fri, 19 Feb 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[Some time back when researching for Backbone JS stuff (I can't remember for what now), I encountered this post Lessons learned while working with Backbone.js.]]></description>
            <content:encoded><![CDATA[<p></p><p>Some time back when researching for <a href="http://backbonejs.org/">Backbone JS</a> stuff (I can't remember for what now), I encountered this post <a href="http://thehungrycoder.com/general/lessons-learned-while-working-with-backbone-js.html">Lessons learned while working with Backbone.js</a>.</p><p></p>
<p></p><p>This post was written a few years back, but I was still able to
glean some gems from it. Specifically, the section "Simplified
Object Copying" was something that could be applied on plain vanilla
JavaScript.</p><p></p>
<p></p><p>The other section "Changing in referenced object does not trigger
events" was something that I had already discovered on my own. The
author's solution was to create a copy of the object to assign to
the model. In my work, I had chosen to manually trigger the
<code>change</code> event. In terms of correctness, I guess creating
a copy and re-assigning to the model would be more so since that
would trigger both the general <code>change</code> event as well as
the <code>change<!-- -->:name</code> event.</p><p></p>
<p></p><p>While I like to think that this could be one of my last posts on
BackboneJS, with <a href="https://angular.io/">Angular JS</a> being
the new hotness, I'm facing a bit of inertia in switching to
Angular. No doubt Angular is newer (I think) and coming from Google,
isn't likely to disappear in oblivion anytime soon, the rapid change
from Angular 1 to 2 is a bit disconcerting. Being a solo developer,
I don't have the luxury of time to always keep chasing after the new
kid on the block.</p><p></p>
<p></p><p>Even though the <a href="https://angular.io/docs/js/latest/quickstart.html">quick start
guide</a> says that npm is only a recommended
component, my guess is that development without npm is going to be
painful. I've never had the chance to truly understand the
ins-and-outs of npm, so I won't be able to work around it
effectively. I always have a resistance to using development
environments that require other components before any effective
coding can start. This means that every time I change a machine, I
always have to run through a (mentally) tedious setup process. It
also means that if I have a different development (one at home and
one at the office), I need to keep the development environments on
both machines the same in order to do my work effectively.</p><p></p>
<p></p><p>So, yah, I guess I'll be sticking with BackboneJS for some time in
the future.</p><p></p>]]></content:encoded>
            <category>backbone</category>
            <category>javascript</category>
            <category>programming</category>
        </item>
        <item>
            <title><![CDATA[Backbone Events]]></title>
            <link>https://www.cheehow.dev/blog/2015/10/27/backbone-events</link>
            <guid>https://www.cheehow.dev/blog/2015/10/27/backbone-events</guid>
            <pubDate>Tue, 27 Oct 2015 00:00:00 GMT</pubDate>
            <description><![CDATA[Backbone events are a]]></description>
            <content:encoded><![CDATA[<p></p><p><a href="http://backbonejs.org/#Events-catalog">Backbone events</a> are a
powerful way to write responsive user interfaces with fewer lines of codes.
This article attempts to give a detailed breakdown of the events and the
parameters available for the callback functions.</p><p></p>
<p></p><p>The results in this article are applicable for version 1.2.3 of<!-- --> <!-- -->
<a href="http://backbonejs.org/">Backbone.js</a></p><p></p>
<p></p><p>The test is performed by instantiating instances of
<code>ExperimentModel</code> extended from
<code>Backbone.Model</code> and <code>ExperimentCollection</code>
extended from <code>Backbone.Collection</code>.</p><p></p>
<p></p><p>The model is first added to the collection to test "add" on the collection and
then a properrty is set on the model.</p><p></p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">var expModelA = new ExperimentModel({ id: 'a' });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var expCollA = new ExperimentCollection();</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<a name="add"></a>
<h3>Add</h3>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">expCollA.on('add', function (model, collection, obj) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">expModelA.on('add', function (model, collection, obj) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">expCollA.add(expModelA);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>In both of the callback functions 3 parameters are passed:</p>
<dl><dt><ol>
<li>
<code>model</code>
</li>
</ol></dt><dd>The model being added to the collection.</dd><dt><ol start="2">
<li>
<code>collection</code>
</li>
</ol></dt><dd><p>The collection <strong>after</strong> the model is added.</p></dd><dt><ol start="3">
<li>
<code>operation object</code>
</li>
</ol></dt><dd><p>A map containing the following keys (and values):</p><ul><li><code>merge (false)</code></li><li><code>add (true)</code></li><li><code>remove (false)</code></li></ul></dd></dl>
<table class="full nice mobile"><thead><tr><th>Event</th><th>Model</th><th>Collection</th></tr></thead><tbody><tr><td><strong>add</strong><br><p>Event is triggered on the model and collection (in this sequence) when
the model is added to the collection.</p></td><td class="ctext add-model"></td><td class="ctext add-collection"></td></tr></tbody></table>
<a name="remove"></a>
<h3>Remove</h3>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">expModelA.on('remove', function (model, collection, obj) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">expCollA.on('remove', function (model, collection, obj) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">expCollA.remove(expModelA);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>In both of the callback functions 3 parameters are passed:</p>
<dl><dt><ol>
<li>
<code>model</code>
</li>
</ol></dt><dd>The model being added to the collection.</dd><dt><ol start="2">
<li>
<code>collection</code>
</li>
</ol></dt><dd><p>The collection <strong>after</strong> the model is added.</p></dd><dt><ol start="3">
<li>
<code>operation object</code>
</li>
</ol></dt><dd><p>A map containing the following key (and value):</p><ul><li><p><code>index</code> (the position in the collection of the model that was
removed).</p></li></ul></dd></dl>
<table class="full nice mobile"><thead><tr><th>Event</th><th>Model</th><th>Collection</th></tr></thead><tbody><tr><td><strong>remove</strong><br><p>Event is triggered on the model and collection (in this sequence) when
the model is removed from the collection.</p></td><td class="ctext remove-model"></td><td class="ctext remove-collection"></td></tr></tbody></table>
<a name="update"></a>
<h3>Update</h3>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">expCollA.on('update', function (collection, obj) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">expCollA.add(expModelA);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">expCollA.remove(expModelA);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p></p><p>The <code>update</code> event is only called on the collection when a model is
added to or removed from the collection. Its callback function receives two
parameters:</p><p></p>
<dl><dt><ol>
<li>
<code>collection</code>
</li>
</ol></dt><dd><p>The collection <strong>after</strong> the model is added.</p></dd><dt><ol start="2">
<li>
<code>operation object</code>
</li>
</ol></dt><dd><p>A map that contains different keys and values depending on the type of
operation (add or remove). See <a href="https://www.cheehow.dev/blog/2015/10/27/backbone-events#add">Add</a> and<!-- --> <!-- -->
<a href="https://www.cheehow.dev/blog/2015/10/27/backbone-events#remove">Remove</a> for details.</p></dd></dl>
<table class="full nice mobile"><thead><tr><th>Event</th><th>Model</th><th>Collection</th></tr></thead><tbody><tr><td><strong>update</strong><br><p>Event is triggered on the collection after
<code>add</code> and <code>remove</code></p></td><td class="ctext update-model"></td><td class="ctext update-collection"></td></tr></tbody></table>
<a name="sort"></a>
<h3>Sort</h3>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">expCollA.on('sort', function (collection, obj) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p></p><p>This event can be triggered when a model is added to/removed from the
collection. It can also be triggered by a call to
<code>sort()</code></p><p></p>
<dl><dt><code>collection</code></dt><dd><p>The collection <strong>after</strong> the model is added.</p></dd><dt><code>operation object</code></dt><dd><p>A map containing the following keys:</p><ul><li><code>merge (boolean)</code></li><li><code>add (boolean)</code></li><li><code>remove (boolean)</code></li></ul><p>The values in this map indicate the operation that occurred that triggered
the event. If this event was triggered by invocation of
<code>sort</code>, this map will be empty.</p></dd></dl>
<table class="full nice mobile"><thead><tr><th>Event</th><th>Model</th><th>Collection</th></tr></thead><tbody><tr><td><strong>sort</strong><br></td><td class="ctext sort-model"></td><td class="ctext sort-collection"></td></tr></tbody></table>
<a name="change"></a>
<h3>Change</h3>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">expModelA.on('change', function (model) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">expCollA.on('change', function (model) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p></p><p>This event is triggered on both the model that was changed, and the collection
that the model is in.</p><p></p>
<dl><dt>model</dt><dd>The model that was changed.</dd></dl>
<table class="full nice mobile"><thead><tr><th>Event</th><th>Model</th><th>Collection</th></tr></thead><tbody><tr><td><strong>change</strong><br></td><td class="ctext change-model"></td><td class="ctext change-collection"></td></tr></tbody></table>
<a name="reset"></a>
<h3>Reset</h3>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">expCollA.on('reset', function (collection, obj) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">expCollA.reset();</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p></p><p>The reset event is invoked by the <code>reset()</code> method. This method
accepts an optional parameter that is the list of models used to replace the
collection. The callback function receives 2 parameters:</p><p></p>
<dl><dt>collection</dt><dd>The collection after the reset operation is completed.</dd><dt>options</dt><dd><p>This object has the <code>previousModels</code> property that holds the
models that were replaced by the <code>reset()</code> operation.</p></dd></dl>
<table class="full nice mobile"><thead><tr><th>Event</th><th>Model</th><th>Collection</th></tr></thead><tbody><tr><td><strong>reset</strong><br></td><td class="ctext reset-model"></td><td class="ctext reset-collection"></td></tr></tbody></table>
<p>(2023 February note: The script below was supposed to update the tables in this page. But since the change to <a href="https://docusaurus.io/" target="_blank" rel="noopener noreferrer">Docusaurus</a>, the needed scripts are no longer available on the page so the code does not work anymore. They are left here for posterity.)</p>
<div class="language-JavaScript language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">script src</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"/js/lib/jquery.min.js"</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">script</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">script src</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"/js/lib/underscore.min.js"</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">script</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">script src</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"/js/lib/backbone.min.js"</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">script</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">$</span><span class="token punctuation" style="color:#393A34">(</span><span class="token dom variable" style="color:#36acaa">document</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">ready</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> tick </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'&amp;#x2713'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> </span><span class="token maybe-class-name">ExperimentModel</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">Backbone</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access maybe-class-name">Model</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">extend</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">defaults</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token literal-property property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function-variable function" style="color:#d73a49">validate</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">attrs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">attrs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'name is required'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> </span><span class="token maybe-class-name">ExperimentCollection</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">Backbone</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access maybe-class-name">Collection</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">extend</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">model</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">ExperimentModel</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Instantiating ExperimentModel A'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> expModelA</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> expModelA </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ExperimentModel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'a'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Alpha'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Instantiating ExperimentCollection A'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> expCollA</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> expCollA </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ExperimentCollection</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expCollA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">comparator</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'name'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expModelA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'change'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">m</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Model: change'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toJSON</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> arguments</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">$</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.change-model'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">html</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tick</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expModelA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'sort'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Model: sort'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> arguments</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expModelA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'reset'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Model: reset'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> arguments</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expModelA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'update'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Model: update'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> arguments</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">$</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.update-model'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">html</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tick</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expModelA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'add'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">m</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> c</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Model: add'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toJSON</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">$</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.add-model'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">html</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tick</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expModelA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'remove'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">m</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> c</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Model: remove'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toJSON</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">$</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.remove-model'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">html</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tick</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expCollA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'change'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">m</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Collection: change'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toJSON</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> arguments</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">$</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.change-collection'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">html</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tick</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expCollA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'sort'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">c</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Collection: sort'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">$</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.sort-collection'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">html</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tick</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expCollA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'reset'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">c</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Collection: reset'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">$</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.reset-collection'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">html</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tick</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expCollA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'update'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">c</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Collection: update'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">$</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.update-collection'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">html</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tick</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">o</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">add</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'ADD'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'REMOVE'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expCollA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'add'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">m</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> c</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Collection: add'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toJSON</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">$</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.add-collection'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">html</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tick</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expCollA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'remove'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">m</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> c</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Collection: remove'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toJSON</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">$</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.remove-collection'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">html</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tick</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//Steps</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Adding model A to collection A'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expCollA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">expModelA</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Setting name on model A'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expModelA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'name'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Experiment A'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Removing model A from collection A'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expCollA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">expModelA</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Unsetting name on model A'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expModelA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">unset</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'name'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Adding model A back to collection A'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expCollA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">expModelA</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Changing name of model A'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expModelA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'name'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Aloha'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Resetting collection A'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expCollA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">reset</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ExperimentModel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'d'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Delta'</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ExperimentModel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'c'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Charlie'</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ExperimentModel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'b'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Bravo'</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">warn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Final length:'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> expCollA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>]]></content:encoded>
            <category>backbone</category>
            <category>javascript</category>
            <category>programming</category>
        </item>
        <item>
            <title><![CDATA[Back to Basics]]></title>
            <link>https://www.cheehow.dev/blog/2015/09/27/back-to-basics</link>
            <guid>https://www.cheehow.dev/blog/2015/09/27/back-to-basics</guid>
            <pubDate>Sun, 27 Sep 2015 00:00:00 GMT</pubDate>
            <description><![CDATA[When I started my formal education in computer science, I had to]]></description>
            <content:encoded><![CDATA[<p>When I started my formal education in computer science, I had to
take a module on programming with the C language. I remember this
was a module that caused many of my peers to re-think their decision
to study computer engineering; the concept of pointers was so
foreign to many of them that even the smart ones scored poorly.</p>
<p>Memory-managed programming languages like Java and PHP have made
memory pointers much less important. For better or worse,
programming has become a much less daunting endeavour now.</p>
<p>As a regular JavaScript writer, I have become used to the
affordances that the myriad array of frameworks have provided in
terms of convenience and abstraction from the nitty-gritty parts of
the language. Instead of writing "straight-up" JavaScript, I just
call a bunch of functions here and there and get the job done in
half the time. So this post is an exercise to recap the basics of
JavaScript.</p>
<p>Just in case you, dear reader, are new to JavaScript, it is a
loosely-typed language. This means that a variable can hold any type
of data.</p>
<p>The types of data in JavaScript are:</p>
<ul>
<li>string</li>
<li>number (integer, float)</li>
<li>boolean</li>
<li>function</li>
<li>object/array</li>
<li><code>null</code></li>
<li><code>undefined</code></li>
</ul>
<p>The first three (string, number and boolean) are primitive types of
the JavaScript language. You never have problems with straight-up
variable assignment with them.</p>
<div class="language-JavaScript language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'string'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//'string'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//'string' because of b = a</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">c</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//retains 1</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>So a variable can be assigned one type (integer) and re-assigned to
another (string) with no confusion.</p>
<p>In a straight-up assignment, you expect <code>b</code> to be updated with the
value of <code>a</code>.</p>
<p>What is not clear to beginners is since <code>c</code> is assigned the
value of <code>b</code>, does changing the value of <code>b</code> affect the value of <code>c</code>?</p>
<p>The answer is <em>no</em> because when an assignment takes place in
JavaScript, the contents are copied over to the assigned variable.</p>
<p>In a language with pointer arithmetic (such as C), things will be
different, and a little complicated, when pointers come into the picture.</p>
<p>Things become interesting when you start working with contents of arrays.</p>
<p>Let's see what happens if the value of the array is assigned to
another variable.</p>
<div class="language-JavaScript language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//shows [3, 2]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//shows [3, 2]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">c</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//shows 1, not 3</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>If you are expecting <code>c</code> to show the value of 3, you are not alone.</p>
<p>What happens here is that when the assignment of <code>c</code> happened, a
copy of the <em>value</em> in <code>b[0]</code> was made and assigned to <code>c</code>.</p>
<p>When <code>b</code> was assigned <code>a</code>, a copy of the <em>location</em> of the array in
memory was made and assigned to <code>b</code>. Thus, when <code>b</code> and <code>a</code> are
referenced, they both point to the same location in memory i.e. the
same array.</p>
<p>In summary, the difference between the examples lies in the fact
that with array values, we are essentially working with memory
locations as compared to actual values.</p>
<p>I'm deferring the use of the terms "pass-by-reference" and
"pass-by-value" here because, like politics, everyone has his/her
own opinions, and everyone disagrees with everyone else's views.
Things become even more complicated when you are talking about a
language that does not have direct memory arithmetic.</p>]]></content:encoded>
            <category>basics</category>
            <category>javascript</category>
            <category>programming</category>
        </item>
        <item>
            <title><![CDATA[AppEngine Header Length Limit]]></title>
            <link>https://www.cheehow.dev/blog/2015/09/06/appengine-header-length-limit</link>
            <guid>https://www.cheehow.dev/blog/2015/09/06/appengine-header-length-limit</guid>
            <pubDate>Sun, 06 Sep 2015 00:00:00 GMT</pubDate>
            <description><![CDATA[I rely heavily on Google AppEngine which is a platform-as-a-service]]></description>
            <content:encoded><![CDATA[<p>I rely heavily on Google AppEngine which is a platform-as-a-service
(PaaS) offering that I can deploy my apps on without having to worry
about the actual server instances powering the application.</p>
<p>Contrast this to infrastructure-as-a-service (IaaS) where I decide
on the number of servers to spin up for my application.</p>
<p>The benefit of a PaaS offering is an abstraction of the underlying
server stuff (and all the nitty gritty server admin issues).</p>
<p>This is great for the developer because the weight of the server
admin hat that you have to wear is made a lot more manageable. The
tradeoff for this abstraction is the lock-in that you have to endure
as a developer.</p>
<p><strong>I'm not familiar with other PaaS providers - my only experience is
with Google AppEngine so I can only speak to that.</strong></p>
<p>On Google AppEngine you are required to write your app using
languages that are supported on the platform e.g. Java, Python, etc.</p>
<p>In addition to being restricted to writing your app in specific
languages, your data must be stored in formats available in that
platform. In the early days of AppEngine this was restricted the
Datastore database.</p>
<p>Trading for all these drawbacks is the huge benefit of not having to
handle the tiny details of administering servers. For a one-man
development team, the value cannot be overstated.</p>
<p>However, being on a specific platform means there are quirks on the
platform that you have to deal with.</p>
<p>This is similar to learning a new language - there are always
strange quirks that you only encounter after you have worked with it deeply enough.</p>
<p>One example of this is the header length limit imposed by AppEngine.
When I was trying to send some data as a HTTP response header, I
realised that my client was unable to get the expected data from the response.</p>
<p>I can't remember exactly how I came across this problem but my
impression was that this limit was only imposed in the actual
deployment but not on the development server.</p>
<p>So after some Googling, I came across this StackOverflow post (
<a href="http://stackoverflow.com/questions/15280027/is-there-a-size-limit-for-http-response-headers-on-google-app-engine" target="_blank" rel="noopener noreferrer">http://stackoverflow.com/questions/15280027/is-there-a-size-limit-for-http-response-headers-on-google-app-engine</a>).
So it seems that there is a limit of 497 characters that can be
placed in the response header (including the colon and the space
after it). Exceeding this limit meant that the header would be dropped.</p>
<p>I thought I would have come across this from Google's documentation
but clearly not. To Google's credit, the documentation is thorough
but sometimes, certain pieces of information need to be made more
obvious so that developers are not caught off guards.</p>]]></content:encoded>
            <category>appengine</category>
            <category>google</category>
        </item>
        <item>
            <title><![CDATA[Converting Certificates]]></title>
            <link>https://www.cheehow.dev/blog/2015/01/13/converting-certificates</link>
            <guid>https://www.cheehow.dev/blog/2015/01/13/converting-certificates</guid>
            <pubDate>Tue, 13 Jan 2015 00:00:00 GMT</pubDate>
            <description><![CDATA[Here's the command this article is talking about:]]></description>
            <content:encoded><![CDATA[<p>Here's the command this article is talking about:</p>
<p>openssl x509 -in proxy.cer -inform der -outform pem -out proxy.crt</p>
<p>This command basically converts a binary certificate into a
base64-encoded one (i.e. text).</p>
<p>The <code>openssl</code> command is the Swiss Army knife of encryption tools.
It can encrypt/decrypt files as well as manage certificates that are
used for secure connections on the Internet.</p>
<p><strong>This command that I've posted does one thing - it converts a
certificate from its binary form into a text form (base64-encoding).</strong></p>
<p>Prior to posting this, I've done my research and have encountered
this command before. The problem is the pages that I've read does
not state it as simply.</p>
<p>Pages that I've read simply say that the above command changes the
DER format of the certificate into the PEM format without going into
details what the PEM format is. After some trial-and-error, I
realised that in very layman terms, the PEM format is a text
representation of the certificate.</p>
<h3>Other commands that might be useful</h3>
<p>openssl x509 -in file.cer -inform der -text -noout</p>
<p>Presents the information (<code>-text</code>) in the certificate (<code>x509</code>) that
is the file (<code>-in file.cer</code>) which is in a binary format (<code>-inform der</code>). Omit the certificate from the output (<code>-noout</code>) - this option
is not required.</p>
<p>openssl dgst -md5 file</p>
<p>Creates a MD5 (<code>-md5</code>) checksum (<code>dgst</code>) of a file (<code>file</code>)</p>
<p>openssl enc -aes-256-cbc -a -nosalt -in infile.jpg -out outfile.jpg.enc</p>
<p>This command encrypts (<code>enc</code>) a file (<code>-in infile.jpg</code>) using the
AES 256-bit cipher block chaining cipher (<code>-aes-256-cbc</code>) with no
salt (<code>-nosalt</code>) into a base-64 format (<code>-a</code>) and saves the output
as a file (<code>-out outfile.jpg.enc</code>).</p>
<p>(Omit the <code>-a</code> switch to keep it in binary format which is almost
always smaller than the equivalent binary format.)</p>
<p>openssl enc -d -aes-256-cbc -a -in outfile.jpg.enc -out newfile.jpg</p>
<p>This is the reverse operation: decrypts (<code>enc -d</code>) a file (<code>-in outfile.jpg.enc</code>) using the same cipher (<code>-aes-256-cbc</code>) from a base-64
format (<code>-a</code>) and saves the output into a file (<code>-out newfile.jpg</code>).</p>
<p>For a list of ciphers:</p>
<p>openssl list-cipher-commands</p>]]></content:encoded>
            <category>bash</category>
            <category>ssl</category>
            <category>tls</category>
            <category>certificate</category>
            <category>programming</category>
        </item>
        <item>
            <title><![CDATA[Hiring Tips]]></title>
            <link>https://www.cheehow.dev/blog/2014/10/03/hiring-tips</link>
            <guid>https://www.cheehow.dev/blog/2014/10/03/hiring-tips</guid>
            <pubDate>Fri, 03 Oct 2014 00:00:00 GMT</pubDate>
            <description><![CDATA[An article I recently read talks about how to hire the right people.]]></description>
            <content:encoded><![CDATA[<p>An article I recently read talks about how to hire the right people.
The TL;DR of it is a list of 7 C's (we all love lists right?):</p>
<ol>
<li>Is the person <em>Competent</em>, with adequate skills and experience to
carry out the role you are recruiting for?</li>
<li>Are they <em>Capable</em> of delivering for you through good times and
bad?</li>
<li>Will the candidate be <em>Compatible</em> with others and build good
relationships with team members, managers and clients?</li>
<li>Do they have the <em>Commitment</em> to make a telling long-term
contribution to your company, or do they bounce from job to job?</li>
<li>What is their <em>Character</em> and do they have personal ethics such
as honesty and integrity?</li>
<li>Will they fit into your company’s <em>Culture</em> and live up to the
expectations you have as an employer?</li>
<li>And lastly, agree on a <em>Compensation</em> package and make sure it is
a satisfactory outcome for both parties.</li>
</ol>
<p>(<strong>Note</strong>: The list above is copied word-for-word from the
article I read. I can’t link to the original article because I received
it in my email.)</p>
<p>One takeaway point from the article is that the interviewer can
begin by first soliciting feedback from customers about the company.
Knowing what are the positive things from the customers’ point of
view will help the interview process by highlighting the positivity
of the company.</p>
<p>Another suggestion in the article is to always interview candidates
before the company needs the manpower. This may be preferable for
large companies but is quite infeasible for small companies.</p>
<p>There is a point that I completely agree with, however - make sure
you like the person. This does not mean that you hire only people
who suck up to you. Rather, the person needs to be compatible with
the company culture. If you hire solely on the basis of technical
competency and aptitude you would eventually end up with someone who
is difficult to work with. When that happens, not only does it make
time in the office more unpleasant, but more importantly, you end up
spending more time arguing and justifying the actions that you need
to make rather than taking action immediately.</p>]]></content:encoded>
            <category>personal</category>
            <category>hiring</category>
            <category>hr</category>
        </item>
    </channel>
</rss>