<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<title>My Blog</title>
	<subtitle>My blog site.</subtitle>
	<link href="https://thadaw.com/posts/feed.xml" rel="self" type="application/atom+xml"/>
    <link href="https://thadaw.com/posts/"/>
	<updated>2026-03-27T00:00:00+00:00</updated>
	<id>https://thadaw.com/posts/feed.xml</id>
	<entry xml:lang="en">
		<title>ทำ Template แรกของ Elysia: Type-Safe ตั้งแต่ Database ถึง Frontend</title>
		<published>2026-03-27T00:00:00+00:00</published>
		<updated>2026-03-27T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/elysia-prisma-spa-template/" type="text/html"/>
		<id>https://thadaw.com/posts/elysia-prisma-spa-template/</id>
		<content type="html">&lt;p&gt;ตอนที่ไปงาน BKK.JS 24 มีโอกาสได้พูดคุยกับออม แล้วก็ถามข้อสงสัยเกี่ยวกับ Elysia หลายอย่างเลยครับ ทำให้เข้าใจความตั้งใจในการออกแบบของออมมากขึ้น ทั้งเรื่องการออกแบบ Framework, การเขียน TypeScript, รวมถึงการ Optimize ต่างๆ&lt;&#x2F;p&gt;
&lt;p&gt;ก่อนหน้านี้ผมมี &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;thaitype-stack-mongodb-template&quot;&gt;Template ที่ใช้อยู่เป็น Next.js + tRPC + MongoDB&lt;&#x2F;a&gt; ซึ่งใช้งานได้ดีครับ แต่พอได้คุยกับออมแล้วเลยคิดว่าน่าจะลองทำ Template อีกตัวที่ใช้ Elysia ดูบ้าง โดยเฉพาะให้มัน AI Friendly ด้วย เพราะตอนนี้ผมใช้ Claude Code กับ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;chief-agent-framework&quot;&gt;Chief Agent Framework&lt;&#x2F;a&gt; ในการเขียนโค้ดเป็นหลักอยู่แล้ว&lt;&#x2F;p&gt;
&lt;p&gt;จุดที่ทำให้ตัดสินใจเลยก็คือตอนที่ออม Demo ให้ดูว่าเราสามารถ infer Type จาก Prisma ได้โดยตรง ทำ Type-Safety ตั้งแต่ระดับ Database จนถึง Frontend เลยทีเดียวครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;type-safety-chain&quot;&gt;Type-Safety Chain&lt;a class=&quot;zola-anchor&quot; href=&quot;#type-safety-chain&quot; aria-label=&quot;Anchor link for: type-safety-chain&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;flow ของ type ใน template ตัวนี้จะเป็นแบบนี้ครับ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; class=&quot;language-text z-code&quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;prisma&#x2F;schema.prisma (single source of truth)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  -&amp;gt; Prisma Client     (TypeScript types)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  -&amp;gt; Prismabox         (TypeBox schemas สำหรับ Elysia validation)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  -&amp;gt; Elysia routes     (body&#x2F;response validation)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  -&amp;gt; Eden Treaty       (type-safe RPC ฝั่ง frontend)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  -&amp;gt; React Query hooks (typed data fetching)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ก็คือ define ที่ Prisma schema ที่เดียว แล้ว type มันก็ไหลไปทั้ง stack เลยครับ ไม่ต้องมานั่งเขียน interface ซ้ำกันทุกชั้น&lt;&#x2F;p&gt;
&lt;p&gt;ตัวอย่างเช่น ใน &lt;code&gt;schema.prisma&lt;&#x2F;code&gt; เรา define Todo model ไว้แค่ที่เดียว แล้วพอรัน &lt;code&gt;prisma generate&lt;&#x2F;code&gt; มันจะ generate ทั้ง Prisma Client types และ TypeBox schemas ผ่าน Prismabox ให้เลย&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;prisma&quot; class=&quot;language-prisma z-code&quot;&gt;&lt;code class=&quot;language-prisma&quot; data-lang=&quot;prisma&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;generator prismabox {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  provider                    = &amp;quot;prismabox&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  typeboxImportDependencyName = &amp;quot;elysia&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  typeboxImportVariableName   = &amp;quot;t&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  inputModel                  = true
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  output                      = &amp;quot;..&#x2F;generated&#x2F;prismabox&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;พอมาฝั่ง route ก็ไม่ต้องเขียน &lt;code&gt;t.Object({...})&lt;&#x2F;code&gt; เองครับ import จาก prismabox แล้วใช้ &lt;code&gt;t.Pick&lt;&#x2F;code&gt; เอา field ที่ต้องการได้เลย&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;TodoPlain&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;TodoPlainInputCreate&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;#generated&#x2F;prismabox&#x2F;Todo&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;CreateTodoBody&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;Pick&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;TodoPlainInputCreate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;title&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;description&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;post&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;user&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;body&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;todoService&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;create&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;user&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;body&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;withAuth&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-true z-ts&quot;&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;body&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;CreateTodoBody&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;response&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;TodoPlain&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ฝั่ง frontend ก็ไม่ต้อง declare Todo type เองเลย ใช้ Eden infer type ให้ได้เลยครับ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;GetTodosResponse&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;Treaty&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Data&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReturnType&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-typeof z-ts&quot;&gt;typeof&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;api&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;api&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;todos&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Todo&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;GetTodosResponse&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-paren z-cover z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;cchudthiiwaaw-macro-kab-plugin-kh-ng-elysia&quot;&gt;จุดที่ว้าว: Macro กับ Plugin ของ Elysia&lt;a class=&quot;zola-anchor&quot; href=&quot;#cchudthiiwaaw-macro-kab-plugin-kh-ng-elysia&quot; aria-label=&quot;Anchor link for: cchudthiiwaaw-macro-kab-plugin-kh-ng-elysia&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จุดที่ว้าวมากๆ ก็คือการที่ออมออกแบบให้มี Escape Hatch สำหรับ Type-Safety ที่ยืดหยุ่นมากครับ&lt;&#x2F;p&gt;
&lt;p&gt;ปัญหาที่เจอใน template ตัวนี้คือผมใช้ Better Auth ซึ่งมัน mount handler แบบ &lt;code&gt;.mount(auth.handler)&lt;&#x2F;code&gt; ทำให้ type ที่ return ออกมาจากฝั่ง server เป็น union type แบบ &lt;code&gt;PayloadType | Response&lt;&#x2F;code&gt; ก็คือ payload ที่เราอยากได้จะ union กับ Response ของ Better Auth ที่ทำพวก &lt;code&gt;&#x2F;api&#x2F;auth&#x2F;*&lt;&#x2F;code&gt; ต่างๆ&lt;&#x2F;p&gt;
&lt;p&gt;ปกติถ้าเจอแบบนี้ก็ต้องมาทำ type cast ใช้ &lt;code&gt;as&lt;&#x2F;code&gt; หรือเขียน type guard วุ่นวายครับ&lt;&#x2F;p&gt;
&lt;p&gt;แต่ Elysia มี Macro ที่ทำให้เรา confirm type จากฝั่ง server ได้เลย แถมสามารถ inject type ลงไปแต่ละ route ได้อีก ผมเลยทำเป็น auth plugin แบบนี้ครับ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;authPlugin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Elysia&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;auth&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;mount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;auth&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;handler&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;macro&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;withAuth&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-async z-ts&quot;&gt;async&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;resolve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;status&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-destructuring z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;headers&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;session&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;auth&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;api&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;getSession&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;headers&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;session&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;401&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;session&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;user&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;พอเอาไปใช้ใน route ก็แค่ใส่ &lt;code&gt;{ withAuth: true }&lt;&#x2F;code&gt; แล้ว &lt;code&gt;user&lt;&#x2F;code&gt; ก็จะอยู่ใน context ให้เลย type safe ทั้งหมด ไม่ต้อง cast อะไรเลยครับ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;user&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;todoService&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;getAll&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;user&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;withAuth&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-true z-ts&quot;&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;response&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;Array&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;TodoPlain&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แบบนี้ route handler return แค่ &lt;code&gt;Todo[]&lt;&#x2F;code&gt; ไม่มี &lt;code&gt;Response&lt;&#x2F;code&gt; มา union ให้วุ่นวาย Eden ฝั่ง frontend ก็เห็น type ถูกต้องไปด้วยเลยครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;stack-thanghmd&quot;&gt;Stack ทั้งหมด&lt;a class=&quot;zola-anchor&quot; href=&quot;#stack-thanghmd&quot; aria-label=&quot;Anchor link for: stack-thanghmd&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Backend &amp;amp; API&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Elysia -- Type-safe web framework on Bun runtime&lt;&#x2F;li&gt;
&lt;li&gt;Prisma v7 -- ORM with SQLite (libsql adapter สำหรับ Bun)&lt;&#x2F;li&gt;
&lt;li&gt;Better Auth -- Authentication library&lt;&#x2F;li&gt;
&lt;li&gt;Prismabox -- Auto-generate TypeBox schemas จาก Prisma&lt;&#x2F;li&gt;
&lt;li&gt;Pino -- Structured logging&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Frontend &amp;amp; UI&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;React 19 -- UI library with Vite bundler&lt;&#x2F;li&gt;
&lt;li&gt;TanStack Router -- File-based routing&lt;&#x2F;li&gt;
&lt;li&gt;Eden Treaty -- Type-safe RPC client สำหรับ Elysia&lt;&#x2F;li&gt;
&lt;li&gt;React Query -- Data fetching and cache management&lt;&#x2F;li&gt;
&lt;li&gt;shadcn&#x2F;ui -- Component library on Radix + Tailwind CSS v4&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ตัว template เป็น SPA ครับ ใช้ TanStack Router อยู่ ใครอยากจะย้ายไปใช้ TanStack Start หรือ React Router ก็ได้ตามถนัดเลย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;l-ngelnkanaid&quot;&gt;ลองเล่นกันได้&lt;a class=&quot;zola-anchor&quot; href=&quot;#l-ngelnkanaid&quot; aria-label=&quot;Anchor link for: l-ngelnkanaid&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; clone https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;thaitype-stack-spa-react-elysia-prisma-template.git&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-cd z-shell&quot;&gt;cd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; thaitype-stack-spa-react-elysia-prisma-template&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;bun&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; install&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; .env.example .env&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;bun&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; run db:push&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;bun&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; run dev&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เปิด http:&#x2F;&#x2F;localhost:3000 สมัครสมาชิก แล้วลองเพิ่ม Todo ดูได้เลยครับ&lt;&#x2F;p&gt;
&lt;p&gt;ก็ถือว่าเป็น Template แรกที่ทำกับ Elysia ครับ อาจจะยังไม่ชำนาญมาก ฝากชี้แนะด้วยนะครับ เดี๋ยวผมเอาไปใช้จริงแล้วจะกลับมาทยอยอัพเดทเรื่อยๆ&lt;&#x2F;p&gt;
&lt;p&gt;GitHub: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;thaitype-stack-spa-react-elysia-prisma-template&quot;&gt;thaitype-stack-spa-react-elysia-prisma-template&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;สวัสดีครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Agent Skill: สอน AI Agent ให้ทำงานที่มันทำไม่ได้</title>
		<published>2026-03-16T00:00:00+00:00</published>
		<updated>2026-03-16T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/agent-skill-teach-ai-to-do-what-it-cant/" type="text/html"/>
		<id>https://thadaw.com/posts/agent-skill-teach-ai-to-do-what-it-cant/</id>
		<content type="html">&lt;p&gt;สวัสดีครับ ช่วงนี้ผมใช้ AI agent ในการเขียนโค้ดเยอะขึ้นมากครับ ไม่ว่าจะเป็น Claude Code, Gemini CLI, Codex หรือ OpenClaw ซึ่งพวกนี้มันฉลาดก็จริง แต่มันก็มีเรื่องง่ายๆ ที่มันทำไม่ได้อยู่หลายอย่าง ผมเลยเริ่มทำสิ่งที่เรียกว่า Agent Skill ขึ้นมาครับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;agent-skill-teach-ai-to-do-what-it-cant&#x2F;cover.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;agent-skill-khuue-aair&quot;&gt;Agent Skill คืออะไร&lt;a class=&quot;zola-anchor&quot; href=&quot;#agent-skill-khuue-aair&quot; aria-label=&quot;Anchor link for: agent-skill-khuue-aair&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ผมมองว่า Skill ก็คือ unit of work ที่เราเขียนไว้ให้ agent เรียกใช้ครับ อารมณ์เหมือนเราเขียน README ให้คนใหม่ในทีมอ่าน บอกว่า &quot;ถ้าเจอเรื่องนี้ ให้รัน script นี้นะ&quot; แต่คนอ่านเป็น AI agent แทน&lt;&#x2F;p&gt;
&lt;p&gt;เวลาเราสั่งอะไร agent มันจะดูก่อนว่าตัวเองมี skill อะไรบ้างที่ตรงกับสิ่งที่เราขอ ถ้ามีก็หยิบมาใช้ ถ้าไม่มีก็ทำแบบ general purpose ไป ซึ่งบางทีก็โอเค แต่บางทีก็พลาด&lt;&#x2F;p&gt;
&lt;p&gt;ตัว skill จริงๆ แล้วก็แค่ไฟล์ markdown ที่อธิบายว่า skill นี้ทำอะไรได้ มี script อะไรให้เรียก พร้อม parameter อะไรบ้าง แล้วก็อาจจะมี script แนบมาด้วย&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; class=&quot;language-text z-code&quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;skill-name&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── SKILL.md           # คำอธิบาย + คำสั่งใช้งาน
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;└── scripts&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    └── some_script.py # script ที่ agent จะเรียก
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แนวคิดนี้ไม่ได้ผูกกับ agent ตัวไหนตัวนึงครับ Claude Code เรียกว่า skill, ตัวอื่นอาจจะเรียกว่า custom instruction หรือ tool definition แต่หลักการเดียวกัน คือเราเขียนคำอธิบายให้ agent อ่าน แล้วมันก็ตัดสินใจเองว่าจะเรียกใช้ตอนไหน&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aipduuniyaamcchring-cchaak-doc-kandiikwaa&quot;&gt;ไปดูนิยามจริงๆ จาก doc กันดีกว่า&lt;a class=&quot;zola-anchor&quot; href=&quot;#aipduuniyaamcchring-cchaak-doc-kandiikwaa&quot; aria-label=&quot;Anchor link for: aipduuniyaamcchring-cchaak-doc-kandiikwaa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ก่อนที่จะไปดูตัวอย่าง ผมอยากลองเทียบกับ doc ของแต่ละเจ้าก่อนครับ ว่าเขานิยาม skill ไว้ว่ายังไงบ้าง&lt;&#x2F;p&gt;
&lt;p&gt;ฝั่ง &lt;strong&gt;Anthropic&lt;&#x2F;strong&gt; เขียนไว้ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;code.claude.com&#x2F;docs&#x2F;en&#x2F;skills&quot;&gt;doc ของ Claude Code&lt;&#x2F;a&gt; ว่า &quot;Skills extend what Claude can do. Create a SKILL.md file with instructions, and Claude adds it to its toolkit.&quot; แล้วก็บอกว่า Claude Code skills follow the &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;agentskills.io&quot;&gt;Agent Skills&lt;&#x2F;a&gt; open standard ซึ่งเป็น open format ที่ใช้ข้ามเครื่องมือได้ โครงสร้างก็ตรงกับที่ผมอธิบายไว้ข้างบน คือ SKILL.md เป็น entrypoint แล้วก็มี scripts&#x2F;, references&#x2F;, assets&#x2F; เสริมได้ สิ่งที่ Claude Code เพิ่มเข้ามาเป็นพิเศษคือ frontmatter ที่ควบคุมได้ว่าใครเป็นคนเรียก skill (เราสั่งเอง หรือให้ Claude ตัดสินใจเอง) และยังรันเป็น subagent แยก context ได้ด้วย&lt;&#x2F;p&gt;
&lt;p&gt;ฝั่ง &lt;strong&gt;OpenAI&lt;&#x2F;strong&gt; ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;developers.openai.com&#x2F;codex&#x2F;skills&#x2F;&quot;&gt;doc ของ Codex&lt;&#x2F;a&gt; ก็เขียนไว้คล้ายกันครับ &quot;A skill packages instructions, resources, and optional scripts so Codex can follow a workflow reliably.&quot; โครงสร้างก็เหมือนกันเลย คือ SKILL.md + scripts&#x2F; + references&#x2F; ที่น่าสนใจคือ Codex บอกว่า custom prompts deprecated ไปแล้ว ให้ใช้ skills แทนสำหรับ reusable instructions&lt;&#x2F;p&gt;
&lt;p&gt;ส่วนฝั่ง &lt;strong&gt;Google&lt;&#x2F;strong&gt; ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;geminicli.com&#x2F;docs&#x2F;cli&#x2F;skills&#x2F;&quot;&gt;Gemini CLI&lt;&#x2F;a&gt; ก็ support Agent Skills เหมือนกัน เขาเขียนว่า skills เป็น &quot;on-demand expertise&quot; ที่ต่างจาก GEMINI.md ตรงที่ไม่ได้โหลดตลอดเวลา แต่จะ activate เมื่อ agent เห็นว่า task ตรงกับ skill description เท่านั้น ซึ่งช่วยไม่ให้ context window รก&lt;&#x2F;p&gt;
&lt;p&gt;ทีนี้พอย้อนกลับมาดู ผมว่าทุกเจ้ามองตรงกันในเรื่องหลักๆ ครับ คือ skill = ไฟล์ markdown ที่อธิบายว่าทำอะไร + script ที่ agent เรียกใช้ได้ แล้วก็เป็น open standard เดียวกันหมด เอาจากเจ้าไหนไปใช้เจ้าไหนก็ได้ สิ่งที่ต่างกันจริงๆ คือ feature เสริมของแต่ละเจ้า เช่น Claude Code มี subagent context, Codex มี agents&#x2F;openai.yaml, Gemini CLI มี discovery tiers แต่ core ของมันก็ยังเป็น SKILL.md เหมือนกันทุกเจ้า&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งตรงกับที่ผมเข้าใจตั้งแต่แรกครับ ผมมอง skill ว่าเป็น &quot;คู่มือที่เขียนให้ AI อ่าน&quot; ไม่ต่างจากที่เราเขียน runbook ให้คนในทีม แค่คนอ่านเปลี่ยนจากมนุษย์เป็น agent แล้ว format ก็ถูก standardize ให้ทุก agent อ่านได้เหมือนกัน&lt;&#x2F;p&gt;
&lt;h2 id=&quot;taw-yaangcchring-skill-thiiphmsraangmaaaiche-ng&quot;&gt;ตัวอย่างจริง: skill ที่ผมสร้างมาใช้เอง&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangcchring-skill-thiiphmsraangmaaaiche-ng&quot; aria-label=&quot;Anchor link for: taw-yaangcchring-skill-thiiphmsraangmaaaiche-ng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ผมจะยกจากของจริงที่ใช้อยู่ครับ ตัวอย่างนี้ผมรันบน Claude Code แต่จะเห็นว่า script ข้างในมันก็แค่ Python ธรรมดา เอาไปใช้กับ agent อะไรก็ได้&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thaamewlaa&quot;&gt;ถามเวลา&lt;a class=&quot;zola-anchor&quot; href=&quot;#thaamewlaa&quot; aria-label=&quot;Anchor link for: thaamewlaa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เรื่องง่ายๆ เลย &quot;ตอนนี้กี่โมง&quot; AI agent ส่วนใหญ่ตอบไม่ได้ครับ เพราะมันไม่มี access เข้า system clock ผมเลยสร้าง skill ชื่อ &lt;code&gt;time&lt;&#x2F;code&gt; ซึ่งข้างในก็แค่บอกให้มันรันคำสั่ง &lt;code&gt;date&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;markdown&quot; class=&quot;language-markdown z-code&quot;&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-block-level z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-heading z-1 z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-begin z-markdown&quot;&gt;#&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-heading z-1 z-markdown&quot;&gt;&lt;span class=&quot;z-entity z-name z-section z-markdown&quot;&gt;time&#x2F;SKILL.md&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-whitespace z-newline z-markdown&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-markdown&quot;&gt;Run the &lt;span class=&quot;z-markup z-raw z-inline z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-begin z-markdown&quot;&gt;`&lt;&#x2F;span&gt;date&lt;span class=&quot;z-punctuation z-definition z-raw z-end z-markdown&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; command to get the current local time.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แค่นี้เลยครับ skill ไม่จำเป็นต้องซับซ้อน ถ้างานมันไม่ซับซ้อน ข้างในก็แค่บอกให้ agent รัน &lt;code&gt;date&lt;&#x2F;code&gt; แล้วเอา output มาตอบเรา&lt;&#x2F;p&gt;
&lt;h3 id=&quot;duu-cost-kh-ng-session&quot;&gt;ดู cost ของ session&lt;a class=&quot;zola-anchor&quot; href=&quot;#duu-cost-kh-ng-session&quot; aria-label=&quot;Anchor link for: duu-cost-kh-ng-session&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;อันนี้เริ่มมีเรื่องให้คิดแล้วครับ ผมอยากรู้ว่า session ที่ใช้อยู่กิน token ไปเท่าไหร่ ต้นทุนประมาณกี่เหรียญ Claude Code บันทึก session เป็นไฟล์ &lt;code&gt;.jsonl&lt;&#x2F;code&gt; ซึ่งข้างในมี token usage ของทุก turn ผมเลยสร้าง skill ชื่อ &lt;code&gt;claude-usage&lt;&#x2F;code&gt; ที่มี Python script ไปอ่านไฟล์นี้ รวม token ทุก turn แล้วคูณ pricing ของแต่ละ model&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;python3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; .claude&#x2F;skills&#x2F;claude-usage&#x2F;scripts&#x2F;usage_summary.py &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;session-id&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;output ออกมาก็ประมาณนี้:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Session: 82c946c8-...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Turns:   100
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Tokens
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    Input:        150
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    Cache write:  447.5k
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    Cache read:   4.22m
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    Output:       23.4k
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Estimated cost: $7.7249
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  By model:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    claude-opus-4-6       23 turns  $5.5371
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    claude-sonnet-4-6     77 turns  $2.1878
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;payhaa-session-id-maacchaakaihn&quot;&gt;ปัญหา: session ID มาจากไหน&lt;a class=&quot;zola-anchor&quot; href=&quot;#payhaa-session-id-maacchaakaihn&quot; aria-label=&quot;Anchor link for: payhaa-session-id-maacchaakaihn&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ทีนี้ &lt;code&gt;claude-usage&lt;&#x2F;code&gt; มันต้องใส่ session ID ครับ แต่พอเราถาม agent ว่า &quot;ตอนนี้ session ID อะไร&quot; มันก็จะบอกว่าไม่รู้ เพราะเป็น internal ที่ agent เข้าถึงไม่ได้&lt;&#x2F;p&gt;
&lt;p&gt;ผมเลยต้องสร้างอีก skill นึงชื่อ &lt;code&gt;claude-session-id&lt;&#x2F;code&gt; ที่ไปหาไฟล์ &lt;code&gt;.jsonl&lt;&#x2F;code&gt; ทั้งหมดแล้วเรียงตาม modification time เพื่อหาว่า session ล่าสุดคืออันไหน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;python3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; .claude&#x2F;skills&#x2F;claude-session-id&#x2F;scripts&#x2F;latest_session.py&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Session ID: 82c946c8-1eb8-4c70-9414-813fc0a278e4
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Date: 2026-03-16 10:32
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Last message (assistant): Here&amp;#39;s the updated README...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;พอมี skill นี้แล้ว ถ้าผมบอกว่า &quot;ดู cost ของ session ปัจจุบันหน่อย&quot; agent ก็จะเรียก &lt;code&gt;claude-session-id&lt;&#x2F;code&gt; ก่อน แล้วเอา ID ที่ได้ไปเรียก &lt;code&gt;claude-usage&lt;&#x2F;code&gt; ต่อ ทำงานเองได้เลย&lt;&#x2F;p&gt;
&lt;p&gt;ตรงนี้เป็นจุดที่น่าสนใจครับ &lt;strong&gt;skill มันต่อกันเป็น chain ได้&lt;&#x2F;strong&gt; โดยที่เราไม่ต้องเขียน orchestration อะไรเลย agent มันจัดการเอง&lt;&#x2F;p&gt;
&lt;h3 id=&quot;todo-management-aebb-structured&quot;&gt;Todo management แบบ structured&lt;a class=&quot;zola-anchor&quot; href=&quot;#todo-management-aebb-structured&quot; aria-label=&quot;Anchor link for: todo-management-aebb-structured&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ตัวอย่างสุดท้ายครับ ผมอยากให้ agent ช่วยจัดการ task สมมติว่าเราไม่สร้าง skill อะไรเลย มันก็จะจดลง markdown แบบ freeform ซึ่งพอ task เยอะขึ้นมันก็จะหาอะไรไม่เจอ update ผิด task ก็มี&lt;&#x2F;p&gt;
&lt;p&gt;ผมเลยสร้าง skill ชื่อ &lt;code&gt;todo&lt;&#x2F;code&gt; ที่เก็บ task เป็น JSONL event log แล้วมี Python script คอยจัดการ add, list, update, delete ให้หมด&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; เพิ่ม task&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;python3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; .claude&#x2F;skills&#x2F;todo&#x2F;scripts&#x2F;tasks.py add&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;title&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Review PR&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;priority&lt;&#x2F;span&gt; P1&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;domain&lt;&#x2F;span&gt; Work&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; ดู task ที่ยังไม่เสร็จ&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;python3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; .claude&#x2F;skills&#x2F;todo&#x2F;scripts&#x2F;tasks.py list&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[ ] [P1] a1b2c3d4  Review PR  [Work]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ข้อดีของการทำแบบนี้คือ agent อ่าน structured data ได้ตรงกว่า freeform markdown มากครับ มันจะ filter ตาม priority, ตาม domain, ตาม status ได้หมด เพราะ data format มันชัดเจน ไม่ต้องมาแกะ markdown เอง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hlakkaar-kaebb-skill&quot;&gt;หลักการออกแบบ skill&lt;a class=&quot;zola-anchor&quot; href=&quot;#hlakkaar-kaebb-skill&quot; aria-label=&quot;Anchor link for: hlakkaar-kaebb-skill&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จากที่ทำมาสักพักผมสรุปได้ประมาณนี้ครับ&lt;&#x2F;p&gt;
&lt;p&gt;อย่างแรกเลยคือ skill นึงควรทำแค่เรื่องนึง อย่าพยายามยัดทุกอย่างลง skill เดียว ถ้าแยกเรื่องได้ก็แยก อย่าง session ID กับ usage ผมแยกเป็นคนละ skill เพราะมันคนละความรับผิดชอบ&lt;&#x2F;p&gt;
&lt;p&gt;อีกเรื่องคือให้ script ทำงานหนักแทน agent ครับ แทนที่จะอธิบายยาวๆ ว่าให้ agent เขียน code อะไร เราเขียน script ให้มันเรียกตรงๆ ดีกว่า ผลลัพธ์ที่ได้จะ consistent กว่าเยอะ ถ้า skill ต้องการ parameter ที่อาจจะมาจาก skill อื่น การรับผ่าน env var อย่าง &lt;code&gt;AGENT_SESSION_ID&lt;&#x2F;code&gt; ก็ทำให้ต่อ chain ได้ง่ายครับ&lt;&#x2F;p&gt;
&lt;p&gt;สุดท้ายคือเรื่อง description ครับ ต้องเขียนให้ชัดเจน เพราะ agent จะอ่าน description ใน skill เพื่อตัดสินใจว่าจะใช้ skill นี้ไหม ถ้า description ไม่ชัด มันก็จะไม่หยิบมาใช้&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ethiiybkabhlakkaarcchaak-official-doc&quot;&gt;เทียบกับหลักการจาก official doc&lt;a class=&quot;zola-anchor&quot; href=&quot;#ethiiybkabhlakkaarcchaak-official-doc&quot; aria-label=&quot;Anchor link for: ethiiybkabhlakkaarcchaak-official-doc&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;พอผมลองไปอ่าน doc และบทความจากหลายเจ้า ก็พบว่าหลักการที่ผมสรุปมามันไปตรงกับที่เขาแนะนำไว้พอสมควรครับ&lt;&#x2F;p&gt;
&lt;p&gt;ฝั่ง OpenAI เขียนไว้ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;developers.openai.com&#x2F;codex&#x2F;skills&#x2F;&quot;&gt;Codex doc&lt;&#x2F;a&gt; ว่า &quot;Keep each skill focused on one job&quot; กับ &quot;Prefer instructions over scripts unless you need deterministic behavior&quot; ซึ่งข้อแรกตรงกับที่ผมทำเลย คือแยก skill ละเรื่อง ส่วนข้อที่สองน่าสนใจ เพราะเขาบอกว่าถ้าไม่จำเป็นต้อง deterministic ก็ให้ใช้ instruction เป็นหลัก แต่จากประสบการณ์ผม ถ้าเป็นงานที่ต้องการ output ตรงกันทุกครั้ง (เช่น คำนวณ cost) ก็ควรเขียน script ดีกว่าจริงๆ ครับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;engineering.block.xyz&#x2F;blog&#x2F;3-principles-for-designing-agent-skills&quot;&gt;บทความจาก Block&lt;&#x2F;a&gt; (ทีมที่ทำ Goose) เขียนหลักการไว้ 3 ข้อที่ผมชอบมากครับ ข้อแรกคือ &quot;Know what the agent should NOT decide&quot; หมายความว่าอะไรที่ต้อง consistent ข้าม run อย่าปล่อยให้ agent คิดเอง ให้ใส่ใน script แทน ข้อที่สองคือ &quot;Know what the agent SHOULD decide&quot; คือปล่อยให้ agent ทำในสิ่งที่มันเก่ง เช่น ตีความ context, สรุปผล, แนะนำ ข้อที่สามคือ &quot;Write a constitution, not a suggestion&quot; เพราะ LLM ชอบทำตัวดีเกินไป ชอบข้ามขั้นตอน หรือเพิ่ม caveat ที่เราไม่ได้ขอ เลยต้องเขียน SKILL.md ให้ชัดเจนเหมือนกฎ ไม่ใช่แค่คำแนะนำ&lt;&#x2F;p&gt;
&lt;p&gt;ส่วนจาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;agentskills.io&quot;&gt;agentskills.io&lt;&#x2F;a&gt; เอง มีจุดที่ผมคิดว่าสำคัญมากคือเรื่อง description ครับ เขาเขียนไว้ว่า &quot;If your skill does not trigger, it is almost never the instructions — it is the description&quot; ซึ่งตรงกับที่ผมบอกเลย description คือ interface จริงๆ ถ้าเขียนไม่ชัด skill ก็จะไม่ถูกเรียกใช้&lt;&#x2F;p&gt;
&lt;p&gt;พอเทียบกันแล้ว ผมว่าหลักการจากประสบการณ์ของผมกับ official doc มันไม่ได้ขัดกันเลยครับ แต่ doc มันให้ framework ที่ชัดกว่า โดยเฉพาะเรื่องการแบ่งว่าอะไรให้ agent ตัดสินใจ อะไรให้ script จัดการ ตรงนี้ช่วยให้ออกแบบ skill ได้ดีขึ้นเยอะ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;l-ngelnaid&quot;&gt;ลองเล่นได้&lt;a class=&quot;zola-anchor&quot; href=&quot;#l-ngelnaid&quot; aria-label=&quot;Anchor link for: l-ngelnaid&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;p&gt;ผม open source skill พวกนี้ไว้ที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;skills&quot;&gt;github.com&#x2F;thaitype&#x2F;skills&lt;&#x2F;a&gt; ครับ ใครอยากลองก็ install ผ่าน degit ได้เลย&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;npx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; degit thaitype&#x2F;skills&#x2F;claude-usage &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.claude&#x2F;skills&#x2F;claude-usage&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ก็หวังว่าจะเป็นประโยชน์กันนะครับ ใครมีไอเดีย skill อะไรมาแชร์กันได้ครับ สวัสดีครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ตั้งค่า AI Agent ส่วนตัวบน Telegram ด้วย PicoClaw + DeepSeek แบบประหยัดสุดๆ</title>
		<published>2026-03-14T00:00:00+00:00</published>
		<updated>2026-03-14T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/setup-personal-ai-agent-telegram-picoclaw-deepseek/" type="text/html"/>
		<id>https://thadaw.com/posts/setup-personal-ai-agent-telegram-picoclaw-deepseek/</id>
		<content type="html">&lt;p&gt;สวัสดีครับ วันก่อนผมได้มีโอกาสไปฟังงาน OpenClaw Meetup ครั้งแรกที่กรุงเทพ ในงานมีหลายๆ คนเข้ามาแชร์ประสบการณ์การใช้ OpenClaw กัน น่าสนใจดี แต่ที่ทำให้ผมหยุดฟังจริงจังเลยคือตอนที่พี่โดมคลาวน์พูดถึง PicoClaw ที่เขียนด้วย Golang เบามากๆ สามารถรันบน VM spec ต่ำๆ ได้ ตอนนั้นผมนั่งฟังแล้วคิดในใจว่า &quot;อันนี้น่าเอามาเล่นจัง&quot;&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งช่วงนี้ผมกำลังออกแบบ Infra Agent แนวๆ OpenClaw อยู่พอดี เลยอยากรู้ว่าพวก Agent Coding อย่าง Claude Code กับ OpenClaw มันต่างกันยังไง แต่ความกังวลของผมก็คือเรื่อง Security ของ OpenClaw นั่นเองที่ทำให้ยังไม่กล้าเอาไปใช้ใน production จริงๆ&lt;&#x2F;p&gt;
&lt;p&gt;เลยก่อนที่จะเริ่มเขียน Agent ตัวใหม่ ผมอยากรู้ว่าตอนนี้เค้าทำกันไปถึงไหนแล้ว เลยมี idea ว่าเอามาใช้งานส่วนตัวกับของที่น่าจะมีผลกับ Security น้อยที่สุดก่อนดีกว่า อย่างเช่นพวก Personal Assistant ที่ช่วยจัดการตารางนัดหมาย ช่วยเตือนความจำ ซึ่งถ้าเกิดปัญหาขึ้นมาก็จะไม่ส่งผลกระทบต่อระบบใหญ่ๆ หรือข้อมูลสำคัญขององค์กร ผมเริ่มจาก Notion skill และ Notion Daily Planner skill ที่ช่วยจัดการ todo list และวางแผนแต่ละวัน อยากรู้ว่า Agent พวกนี้ทำได้แค่ไหน มีข้อจำกัดอะไรบ้าง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thamaimthuengeluue-k-picoclaw&quot;&gt;ทำไมถึงเลือก PicoClaw&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaimthuengeluue-k-picoclaw&quot; aria-label=&quot;Anchor link for: thamaimthuengeluue-k-picoclaw&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เหตุผลตรงๆ เลยคือ cost ผมน้อย 5555 เลยเลือก solution ที่ถูกที่สุดก็คือสร้าง VM บน DigitalOcean ราคา $4&#x2F;เดือน CPU 1 core, RAM 512MB แล้วก็ใช้ PicoClaw รัน Agent ของผมบน VM นั้นเลย เพราะเจ้า PicoClaw ใช้ spec ต่ำมากๆ น่าจะเหมาะกับ VM ราคาถูกๆ แบบนี้ได้ดีเลยทีเดียว&lt;&#x2F;p&gt;
&lt;p&gt;ส่วน model ก็เลือกจาก OpenRouter Ranking ที่มีคนใช้งานเยอะๆ และราคาไม่แพง แต่ก็ควรจะเก่งประมาณนึง เลยไปถูกใจกับเจ้า DeepSeek V3.2 ที่ราคาไม่แพงมาก ราคาประมาณ $0.26&#x2F;M input tokens กับ $0.38&#x2F;M output tokens ซึ่งเท่าที่หาๆ มาพบว่าสามารถสู้กับ GPT-5 ได้เลยทีเดียว (ถาม AI เอานะ อันนี้ไม่ชัวร์เท่าไหร่ 555)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tidtang-picoclaw&quot;&gt;ติดตั้ง PicoClaw&lt;a class=&quot;zola-anchor&quot; href=&quot;#tidtang-picoclaw&quot; aria-label=&quot;Anchor link for: tidtang-picoclaw&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ตรงนี้ไม่มีอะไรซับซ้อนครับ โหลด .deb มาลงได้เลย (ณ ตอนที่เขียนเป็นเวอร์ชั่น 0.2.2):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;p&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;apps&#x2F;picoclaw&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-and z-shell&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-cd z-shell&quot;&gt;cd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;apps&#x2F;picoclaw&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;wget&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; https:&#x2F;&#x2F;github.com&#x2F;sipeed&#x2F;picoclaw&#x2F;releases&#x2F;download&#x2F;v0.2.2&#x2F;picoclaw_x86_64.deb&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; dpkg&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; picoclaw_x86_64.deb&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;picoclaw&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;help&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;setup-telegram-bot&quot;&gt;Setup Telegram Bot&lt;a class=&quot;zola-anchor&quot; href=&quot;#setup-telegram-bot&quot; aria-label=&quot;Anchor link for: setup-telegram-bot&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ต่อไปคือเชื่อม PicoClaw เข้ากับ Telegram ครับ ขั้นตอนไม่ยาก แต่มีหลายจุดที่ต้องไปหยิบ token&#x2F;ID มา เลยเขียนไว้ให้ทีละ step:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-sraang-bot&quot;&gt;1. สร้าง Bot&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-sraang-bot&quot; aria-label=&quot;Anchor link for: 1-sraang-bot&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;เปิด Telegram แล้วค้นหา &lt;code&gt;@BotFather&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ส่ง &lt;code&gt;&#x2F;newbot&lt;&#x2F;code&gt; แล้วทำตามขั้นตอน&lt;&#x2F;li&gt;
&lt;li&gt;Copy bot token เก็บไว้&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;2-haa-user-id-kh-ngtawe-ng&quot;&gt;2. หา User ID ของตัวเอง&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-haa-user-id-kh-ngtawe-ng&quot; aria-label=&quot;Anchor link for: 2-haa-user-id-kh-ngtawe-ng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ส่งข้อความหา &lt;code&gt;@userinfobot&lt;&#x2F;code&gt; บน Telegram แล้วจดเลข User ID ไว้ครับ ตรงนี้สำคัญ เพราะเราจะเอาไปใส่ใน config เพื่อบอกว่าให้ bot คุยกับ user id นี้เท่านั้น&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-config-picoclaw&quot;&gt;3. Config PicoClaw&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-config-picoclaw&quot; aria-label=&quot;Anchor link for: 3-config-picoclaw&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ส่วนที่สำคัญที่สุดของการ setup คือไฟล์ &lt;code&gt;~&#x2F;.picoclaw&#x2F;config.json&lt;&#x2F;code&gt; ครับ:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json z-code&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;agents&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;defaults&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;model_name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;openrouter-deepseek-v3.2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;model_list&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;    &lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;model_name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;openrouter-deepseek-v3.2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;model&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;openrouter&#x2F;deepseek&#x2F;deepseek-v3.2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;api_base&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;https:&#x2F;&#x2F;openrouter.ai&#x2F;api&#x2F;v1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;api_key&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;YOUR_OPENROUTER_API_KEY&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;channels&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;telegram&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;enabled&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;token&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;YOUR_BOT_TOKEN&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;allow_from&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;YOUR_USER_ID&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;agents.defaults.model_name&lt;&#x2F;code&gt; ใช้เลือกว่าจะใช้ model ไหนจาก &lt;code&gt;model_list&lt;&#x2F;code&gt; ครับ&lt;&#x2F;p&gt;
&lt;p&gt;ส่วน config ของ Telegram channel:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;&#x2F;th&gt;&lt;th&gt;คำอธิบาย&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;enabled&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;เปิด&#x2F;ปิด channel&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;token&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Bot token จาก @BotFather&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;allow_from&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;User ID ที่อนุญาตให้ใช้งาน (ปล่อยว่างไว้ = ใครก็ใช้ได้)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;4-ran&quot;&gt;4. รัน&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-ran&quot; aria-label=&quot;Anchor link for: 4-ran&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;picoclaw&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; gateway&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เปิด Telegram ไปที่ bot แล้วกด &lt;strong&gt;Start&lt;&#x2F;strong&gt; ได้เลยครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tang-timezone&quot;&gt;ตั้ง Timezone&lt;a class=&quot;zola-anchor&quot; href=&quot;#tang-timezone&quot; aria-label=&quot;Anchor link for: tang-timezone&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;อันนี้ผมลืมตอนแรกครับ 555 พอถาม Lucia ว่ากี่โมงแล้ว มันตอบมาเวลา UTC ผิดไป 7 ชั่วโมง จริงๆ ถ้าใครทำ server มาปกติเราจะ setup เป็น UTC+0 ไว้ แต่ผมเน้นไวขอแบบแก้ง่ายๆ ละกัน เลยแก้ที่ timezone ของเครื่องเลย (จริงๆ มันตั้งค่าที่ PicoClaw ได้นะ แต่ขี้เกียจไปหา 555):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; timedatectl set-timezone Asia&#x2F;Bangkok&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;timedatectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;aih-picoclaw-ran-auto-start-dwy-systemd&quot;&gt;ให้ PicoClaw รัน Auto-Start ด้วย systemd&lt;a class=&quot;zola-anchor&quot; href=&quot;#aih-picoclaw-ran-auto-start-dwy-systemd&quot; aria-label=&quot;Anchor link for: aih-picoclaw-ran-auto-start-dwy-systemd&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;พอลองรันครั้งแรกก็ใช้ได้ดีครับ แต่พอปิด terminal แล้ว PicoClaw ก็ตายตามไปด้วย ซึ่งแบบนี้ก็ไม่ได้เรื่อง เลยต้อง setup ให้รันเป็น service:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sraang-service-file&quot;&gt;สร้าง service file&lt;a class=&quot;zola-anchor&quot; href=&quot;#sraang-service-file&quot; aria-label=&quot;Anchor link for: sraang-service-file&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; nano &#x2F;etc&#x2F;systemd&#x2F;system&#x2F;picoclaw.service&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;ini&quot; class=&quot;language-ini z-code&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Unit]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;PicoClaw Gateway
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;After&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;network&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;target
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Service]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;Type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;simple
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;User&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-constant z-genconfig&quot;&gt;YOUR_USERNAME&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;usr&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;bin&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;&#x2F;&lt;&#x2F;span&gt;picoclaw gateway
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;Restart&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;on&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;-&lt;&#x2F;span&gt;failure
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;RestartSec&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-genconfig&quot;&gt;5&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-storage z-type z-genconfig&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-genconfig&quot;&gt;&lt;span class=&quot;z-meta z-param z-genconfig&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-genconfig&quot;&gt;WantedBy&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;multi&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;-&lt;&#x2F;span&gt;user&lt;span class=&quot;z-keyword z-operator z-genconfig&quot;&gt;.&lt;&#x2F;span&gt;target
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;อย่าลืมเปลี่ยน &lt;code&gt;YOUR_USERNAME&lt;&#x2F;code&gt; เป็น username ของตัวเองนะครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;enable-aela-start&quot;&gt;Enable และ start&lt;a class=&quot;zola-anchor&quot; href=&quot;#enable-aela-start&quot; aria-label=&quot;Anchor link for: enable-aela-start&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; systemctl daemon-reload&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; systemctl enable picoclaw&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; systemctl start picoclaw&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เช็คสถานะ:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; systemctl status picoclaw&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ดู log:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; journalctl&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;u&lt;&#x2F;span&gt; picoclaw&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;kamhndtawtnaih-agent&quot;&gt;กำหนดตัวตนให้ Agent&lt;a class=&quot;zola-anchor&quot; href=&quot;#kamhndtawtnaih-agent&quot; aria-label=&quot;Anchor link for: kamhndtawtnaih-agent&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ก่อนจะไปเขียน Skill อย่างแรกที่ควรทำคือกำหนดตัวตนให้ Agent ก่อนครับ ใน PicoClaw เราสามารถเขียนไฟล์ Markdown พวก SOUL.md, IDENTITY.md, USER.md ไว้ใน workspace เพื่อบอกให้ Agent รู้ว่ามันเป็นใคร พูดยังไง และกำลังคุยกับใคร ในที่นี้ผมตั้งชื่อว่า &quot;Lucia&quot; ครับ ตรงนี้จะช่วยให้ bot มีบุคลิกที่สม่ำเสมอทุกครั้งที่คุยด้วย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;s-naih-lucia-thamngaandwy-skills&quot;&gt;สอนให้ Lucia ทำงานด้วย Skills&lt;a class=&quot;zola-anchor&quot; href=&quot;#s-naih-lucia-thamngaandwy-skills&quot; aria-label=&quot;Anchor link for: s-naih-lucia-thamngaandwy-skills&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;พอ PicoClaw รันได้และกำหนดตัวตนให้เรียบร้อยแล้ว ส่วนที่สนุกที่สุดก็มาถึงครับ คือการเขียน Skill ให้มัน&lt;&#x2F;p&gt;
&lt;p&gt;ผมรู้สึกว่า PicoClaw มันคิดมาดีตรงที่ Skill มันก็คือไฟล์ Markdown ที่อธิบายให้ Agent รู้ว่าต้องทำอะไรยังไง อารมณ์เหมือนเขียน prompt แต่มีโครงสร้างชัดเจนกว่า ผมเริ่มจากเขียน 2 skill:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;notion-skill&quot;&gt;Notion Skill&lt;a class=&quot;zola-anchor&quot; href=&quot;#notion-skill&quot; aria-label=&quot;Anchor link for: notion-skill&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ตัวนี้สอนให้ Lucia ใช้ Notion API ได้ครับ เช่น ค้นหาหน้า สร้าง page ใหม่ อัพเดท task โดยเก็บ API key ไว้ที่ &lt;code&gt;~&#x2F;.picoclaw&#x2F;workspace&#x2F;secret&#x2F;notion&#x2F;api_key&lt;&#x2F;code&gt; ซึ่ง skill นี้ผม fork มาจาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;clawhub.ai&#x2F;steipete&#x2F;notion&quot;&gt;clawhub.ai&#x2F;steipete&#x2F;notion&lt;&#x2F;a&gt; แล้วมาปรับให้เข้ากับ Notion API version ล่าสุด ดูตัวอย่าง skill ได้ที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;blog-v8&#x2F;blob&#x2F;main&#x2F;content&#x2F;posts&#x2F;2026-03-14-setup-personal-ai-agent-telegram-picoclaw-deepseek&#x2F;skills&#x2F;notion&#x2F;SKILL.md&quot;&gt;Notion SKILL.md&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;notion-daily-planner-skill&quot;&gt;Notion Daily Planner Skill&lt;a class=&quot;zola-anchor&quot; href=&quot;#notion-daily-planner-skill&quot; aria-label=&quot;Anchor link for: notion-daily-planner-skill&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ตัวนี้ผมเขียนเองต่อยอดจาก Notion Skill ครับ เพิ่มความสามารถในการจัดการ task ตาม Eisenhower Matrix (P0-P3) และสร้างแผนประจำวัน โดยมี cache เป็น CSV ไว้ในเครื่องเพื่อลดการเรียก API ซึ่งแบบนี้ทำให้ bot ตอบเร็วขึ้นเยอะ ไม่ต้องไปดึง Notion ทุกครั้ง ดูตัวอย่าง skill ได้ที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;blog-v8&#x2F;blob&#x2F;main&#x2F;content&#x2F;posts&#x2F;2026-03-14-setup-personal-ai-agent-telegram-picoclaw-deepseek&#x2F;skills&#x2F;notion-daily-planner&#x2F;SKILL.md&quot;&gt;Notion Daily Planner SKILL.md&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;phllaphththiiaid&quot;&gt;ผลลัพธ์ที่ได้&lt;a class=&quot;zola-anchor&quot; href=&quot;#phllaphththiiaid&quot; aria-label=&quot;Anchor link for: phllaphththiiaid&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;พอทุกอย่างพร้อม ผมก็ลองคุยกับ Lucia ผ่าน Telegram ดูครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;khuythawaip-duu-resource-vm&quot;&gt;คุยทั่วไป + ดู resource VM&lt;a class=&quot;zola-anchor&quot; href=&quot;#khuythawaip-duu-resource-vm&quot; aria-label=&quot;Anchor link for: khuythawaip-duu-resource-vm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;setup-personal-ai-agent-telegram-picoclaw-deepseek&#x2F;telegram-basic-chat.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ลอง list top 3 processes ที่กิน resource เยอะที่สุดบน VM ก็ตอบมาได้เลย ตัว PicoClaw เองใช้ memory แค่ 19MB เท่านั้น ผมเห็นตัวเลขนี้แล้วก็คิดว่า VM ราคา $4 นี่เหลือเฟือเลยครับ แล้วก็ถามว่ามี skill อะไรบ้าง ก็โชว์มาครบ 8 ตัว&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cchadkaar-task-ain-notion&quot;&gt;จัดการ task ใน Notion&lt;a class=&quot;zola-anchor&quot; href=&quot;#cchadkaar-task-ain-notion&quot; aria-label=&quot;Anchor link for: cchadkaar-task-ain-notion&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;setup-personal-ai-agent-telegram-picoclaw-deepseek&#x2F;telegram-task-planner.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ตรงนี้คือสิ่งที่ทำให้ผมรู้สึกว้าวนะครับ ลองบอกให้ list task ที่ข้อมูลยังไม่ครบ Lucia ก็ไปดึงจาก Notion มา (มี 50 task) แล้วเลือกมา 5 ตัวที่ข้อมูลไม่ครบ พร้อมแนะนำว่าควรเติมอะไร เช่น Priority, Due Date, Domain พอผมบอกว่าอัพเดทตามคำแนะนำเลย ก็ไปแก้ใน Notion ให้จริงๆ ครับ ไม่ต้องเปิด Notion เองเลย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;khaaaichcchaaythanghmd&quot;&gt;ค่าใช้จ่ายทั้งหมด&lt;a class=&quot;zola-anchor&quot; href=&quot;#khaaaichcchaaythanghmd&quot; aria-label=&quot;Anchor link for: khaaaichcchaaythanghmd&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;รายการ&lt;&#x2F;th&gt;&lt;th&gt;ราคา&#x2F;เดือน&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;DigitalOcean VM (1 core, 512MB)&lt;&#x2F;td&gt;&lt;td&gt;$4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;DeepSeek V3.2 via OpenRouter&lt;&#x2F;td&gt;&lt;td&gt;ลองคุยเล่น 4 ชม. หมดไป $1.2 (ประมาณ 5M token)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;รวม&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;~$4-5&#x2F;เดือน&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;k-ncchaakkan&quot;&gt;ก่อนจากกัน&lt;a class=&quot;zola-anchor&quot; href=&quot;#k-ncchaakkan&quot; aria-label=&quot;Anchor link for: k-ncchaakkan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;กลับมาที่ตอนนั่งฟังพี่โดมคลาวน์พูดในวันนั้นครับ ตอนแรกผมแค่อยากรู้ว่า Agent พวกนี้ทำได้แค่ไหน เลยลองเริ่มจากของส่วนตัวที่ถ้าพังก็ไม่เจ็บ ผลคือได้ Personal Assistant ที่ใช้งานผ่าน Telegram ได้จริง ค่าใช้จ่ายเดือนละไม่ถึงร้อยบาท ตัว PicoClaw ใช้ memory แค่ 19MB รันบน VM ราคา $4 ยังเหลือเฟือ ส่วนเรื่อง Security ที่ผมกังวลตอนแรก พอลองใช้จริงก็พบว่าการเริ่มจาก use case ที่ไม่ sensitive มันช่วยให้เราเข้าใจข้อจำกัดของ Agent ได้ดีขึ้นโดยไม่ต้องเสี่ยงกับของจริง ถ้าใครอยากลองทำ Personal Agent แบบประหยัดๆ บ้าง ลองดู PicoClaw ได้ครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>เพราะคนเราผิดพลาดกันได้ ระบบจึงสำคัญ</title>
		<published>2026-01-12T00:00:00+00:00</published>
		<updated>2026-01-12T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/because-humans-can-make-mistakes-systems-are-important/" type="text/html"/>
		<id>https://thadaw.com/posts/because-humans-can-make-mistakes-systems-are-important/</id>
		<content type="html">&lt;p&gt;พอดีวันนี้เป็นวันพักผ่อนสบายๆ ของผมที่เชียงใหม่ครับ ระหว่างที่กำลังเดินเล่นเรื่อยๆ ผมก็บังเอิญเห็นกุญแจเสียบคาไว้อยู่หน้าร้าน ถ้าดูเผินๆ เหมือนไม่มีอะไร แต่กลับทำให้ผมหยุดคิดอยู่แปปนึง เพราะสื่อถึงระบบความปลอดภัยที่พึ่งพามนุษย์นั่นเอง ภาพนั้นไปเชื่อมกับเรื่องที่ผมเพิ่งพูดไปเมื่อวันเสาร์ที่ผ่านมา ในงาน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.facebook.com&#x2F;cnx.techontherock&quot;&gt;Northern Tech on the Rock&lt;&#x2F;a&gt; เรื่อง Secret และความปลอดภัยของระบบพอดี เลยคิดว่า นี่น่าจะเป็นโอกาสดีที่จะหยิบเรื่องนั้นมาเล่าต่อในรูปแบบ Blog ละกันนะ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;because-humans-can-make-mistakes-systems-are-important&#x2F;cover.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;หลายคนพอได้ยินคำว่า Secret หรือความปลอดภัยของระบบ ก็มักจะนึกถึงเรื่องเทคนิคทันที ทั้ง API key, password หรือ token ต่างๆ ซึ่งก็ไม่ผิดนะครับ แต่มุมที่ผมอยากชวนคิดจริงๆ คือ เรากำลังพึ่งพา “ระบบ” แค่ไหน หรือว่าสุดท้ายแล้วยังพึ่งพา “ความระวังของคน” อยู่เป็นหลัก เหมือนกับกุญแจที่เสียบคาไว้นั่นแหละ ไม่ได้ผิดขั้นตอนอะไรเลย แค่หวังว่าทุกคนจะช่วยกันไม่พลาด ซึ่งในโลกของระบบซอฟต์แวร์ พอทุกอย่างเริ่มซับซ้อนขึ้น แนวคิดแบบนี้มักจะพาเราไปเจอปัญหาเดิมๆ ซ้ำแล้วซ้ำอีกครับ&lt;&#x2F;p&gt;
&lt;p&gt;ปัญหาคือ เวลาที่ระบบยังเล็กอยู่ วิธีคิดแบบนี้มันดูเวิร์กมากครับ Secret มีไม่กี่ตัว ทุกคนรู้ว่าเก็บไว้ตรงไหน ใครต้องใช้ก็ทักถามกันเอา พอมีอะไรผิดพลาดก็ยังพอไล่กันทัน แต่พอระบบเริ่มโตขึ้น มีหลายแอป หลาย environment และมีคนเข้ามาเกี่ยวข้องมากขึ้น ความ “หวังดีต่อกัน” แบบเดิมๆ ก็เริ่มไม่พอ Secret ตัวเดิมอาจถูกนำไปใช้ซ้ำในหลายที่ สิทธิ์การเข้าถึงค่อยๆ ถูกขยายออกเพื่อความสะดวก จนสุดท้ายเราเองก็ไม่แน่ใจแล้วว่า ใครเข้าถึงอะไรได้บ้าง และถ้าวันหนึ่งมันเกิดหลุดขึ้นมา เราจะรู้ตัวตอนไหนครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;watcchakrchiiwitkh-ng-secret-secret-lifecycle&quot;&gt;วัฏจักรชีวิตของ Secret (Secret Lifecycle)&lt;a class=&quot;zola-anchor&quot; href=&quot;#watcchakrchiiwitkh-ng-secret-secret-lifecycle&quot; aria-label=&quot;Anchor link for: watcchakrchiiwitkh-ng-secret-secret-lifecycle&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ตรงนี้แหละครับที่ผมเริ่มรู้สึกว่า เรามักมอง Secret เป็นแค่ “ค่า” ค่าเดียวในไฟล์ config หรือค่าหนึ่งในระบบจัดการ secret แต่ในความเป็นจริง Secret ไม่ได้อยู่นิ่งๆ แบบนั้นเลย มันมีช่วงเวลาของมัน มีวันเกิด มีช่วงที่ถูกใช้งาน มีวันที่ควรหมดอายุ และมีวันที่ควรถูกเปลี่ยนหรือเลิกใช้ไป ถ้าเรามองมันเป็นแค่ค่าหนึ่ง แล้วหวังว่าทุกคนจะจำได้เองว่าเมื่อไหร่ควรเปลี่ยน เมื่อไหร่ควรปิด เราก็กลับไปอยู่จุดเดียวกับกุญแจที่เสียบคาไว้นั่นแหละครับ คือไม่ได้ผิดในทันที แต่รอวันที่ความผิดพลาดจะเกิดขึ้น&lt;&#x2F;p&gt;
&lt;pre class=&quot;mermaid&quot;&gt;
  flowchart LR
  %% Secret Lifecycle
  subgraph L[Secret Lifecycle]
    direction LR

    C[Create] --&amp;gt; S[Store]
    S --&amp;gt; B[Consume]
    B --&amp;gt; E[&amp;quot;Expired&amp;lt;br&amp;gt;(signal: rotation needed)&amp;quot;]
    E --&amp;gt; R[Rotate]
    R --&amp;gt; D[Destroy]
    D --&amp;gt; C
  end

  %% Cross-cutting concerns (not part of lifecycle)
  subgraph X[Cross-cutting Concerns]
    direction TB
    SC[&amp;quot;Scope&amp;lt;br&amp;gt;(env&amp;#x2F;app boundary)&amp;quot;]
    P[&amp;quot;Permission&amp;lt;br&amp;gt;(least privilege)&amp;quot;]
    I[&amp;quot;Identity&amp;lt;br&amp;gt;(Service Principal &amp;#x2F; Managed Identity)&amp;quot;]
    RV[&amp;quot;Revoke Access&amp;lt;br&amp;gt;(disable access without deleting secret)&amp;quot;]
    AU[&amp;quot;Audit Logs &amp;#x2F; Alerts&amp;lt;br&amp;gt;(who, when, what)&amp;quot;]
  end
&lt;&#x2F;pre&gt;
&lt;p&gt;พอเราเริ่มมอง Secret ในมุมของเวลา ปัญหามันก็เปลี่ยนไปทันที เพราะสิ่งที่ต้องจัดการไม่ใช่แค่การ “เก็บให้ปลอดภัย” อย่างเดียวอีกต่อไป แต่รวมถึงว่า ใครเป็นคนสร้าง ใครมีสิทธิ์ใช้ ใครมีสิทธิ์เปลี่ยน แล้วถ้าวันหนึ่งต้องยกเลิกหรือหมุนเวียน Secret นั้น ระบบจะพาเราไปถึงจุดนั้นได้เองหรือเปล่า หรือสุดท้ายก็ต้องกลับไปพึ่งคนเดิมๆ มานั่งไล่แก้ทีละจุด ถ้ายังเป็นแบบหลังอยู่ ต่อให้มีเครื่องมือดีแค่ไหน เราก็ยังหนีปัญหาเดิมไม่พ้นครับ&lt;&#x2F;p&gt;
&lt;p&gt;สุดท้ายแล้ว ผมคิดว่าปัญหาจริงๆ ไม่ได้อยู่ที่เรามี Secret เยอะเกินไป แต่อยู่ที่เราไม่มีระบบมารองรับมันต่างหาก ตอนที่ Secret มีแค่ไม่กี่ตัว ทุกอย่างดูง่ายไปหมด แต่พอจำนวนมันค่อยๆ เพิ่มขึ้น สิ่งที่ตามมาคือความซับซ้อนที่เราไม่ค่อยรู้ตัว และเพื่อให้จัดการง่ายขึ้น เรามักเลือกทางลัด เช่น ขยายสิทธิ์ให้กว้างขึ้น ใช้ Secret เดียวกันในหลายที่ หรือปล่อยให้มันอยู่ไปเรื่อยๆ โดยหวังว่าจะไม่มีอะไรเกิดขึ้น ซึ่งวิธีเหล่านี้อาจช่วยให้ระบบเดินต่อได้ในระยะสั้น แต่ในระยะยาวมันกำลังสะสมความเสี่ยงไว้เงียบๆ ครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;taw-yaangain-workshop&quot;&gt;ตัวอย่างใน Workshop&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangain-workshop&quot; aria-label=&quot;Anchor link for: taw-yaangain-workshop&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;อย่างใน Workshop ที่ผ่านมานี่ ผมยกตัวอย่างง่ายๆ ด้วยการใช้ TypeScript เขียนเป็นสคริปต์ตัวหนึ่ง แล้วให้มันไปจัดการเรื่อง Secret ผ่าน Azure Key Vault จากนั้นก็เอาไปใช้งานจริงตอน Deploy บน Azure Container App โดยรันผ่าน GitHub Actions จุดที่อยากให้เห็นไม่ใช่ตัวโค้ดหรือเครื่องมือเป็นหลัก แต่คือภาพรวมของการทำงานทั้งระบบ ว่า Secret ถูกสร้าง เก็บ และถูกนำไปใช้ยังไงบ้าง&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;because-humans-can-make-mistakes-systems-are-important&#x2F;workshop.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ใน Workshop ผมเลยตั้งใจโชว์ให้เห็นเรื่อง Secret Lifecycle แบบครบๆ ทั้งการกำหนดสิทธิ์ การจำกัด Scope และการควบคุมการเข้าถึงในแต่ละขั้น เพื่อให้เห็นว่า ถ้าเราออกแบบระบบมาดี มันจะช่วยลดการพึ่งพาความระวังของคนลงได้เยอะมาก และปล่อยให้ระบบทำหน้าที่ดูแลความปลอดภัยแทนเราได้มากขึ้นครับ&lt;&#x2F;p&gt;
&lt;p&gt;แต่พอถอยออกมามองในมุมขององค์กรจริงๆ จะเห็นว่า วิธีจัดการเรื่อง Secret ของแต่ละที่แตกต่างกันมาก บางที่มีเครื่องมือครบ มีระบบพร้อม แต่สุดท้ายก็ยังพึ่งพาการตกลงกันด้วยปากเปล่า หรือเอกสารเป็นหลัก ในขณะที่บางที่อาจจะไม่ได้มีเครื่องมือหวือหวาอะไร แต่กลับออกแบบกติกาให้ระบบบังคับใช้งานตั้งแต่ต้น ซึ่งจากที่ผมเจอมาบ่อยๆ ความแตกต่างตรงนี้ไม่ได้อยู่ที่ว่าเลือกใช้เครื่องมืออะไร แต่อยู่ที่ว่าเราเลือกจะย้ายความรับผิดชอบจาก “คน” ไปไว้ที่ “ระบบ” มากแค่ไหนครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;withiikhidaebb-soft-constraint&quot;&gt;วิธีคิดแบบ Soft Constraint&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiikhidaebb-soft-constraint&quot; aria-label=&quot;Anchor link for: withiikhidaebb-soft-constraint&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ถ้าลองสังเกตดูดีๆ วิธีจัดการเรื่อง Secret ส่วนใหญ่มักจะตกอยู่ในสองแนวทางนี้ แนวทางแรกคือแบบที่เราคุ้นเคยกันดี คือมีกฎ มีแนวปฏิบัติ มีเอกสารบอกว่าอะไรควรหรือไม่ควรทำ ทุกคนรู้กติกา และก็หวังว่าทุกคนจะทำตามให้ถูกต้อง วิธีแบบนี้ผมเรียกว่า Soft constraint ไม่ได้ผิดอะไรเลย แถมยังเริ่มต้นได้เร็ว ต้นทุนต่ำ และเหมาะกับช่วงที่ระบบยังเล็กอยู่ แต่ข้อจำกัดของมันก็คือ ทุกอย่างยังต้องอาศัยความระมัดระวังและวินัยของคนเป็นหลัก ซึ่งถ้าวันไหนพลาดขึ้นมา ระบบก็ไม่ค่อยมีอะไรช่วยเตือนหรือช่วยกันพลาดเท่าไหร่ครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;withiikhidaebb-hard-constraint&quot;&gt;วิธีคิดแบบ Hard Constraint&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiikhidaebb-hard-constraint&quot; aria-label=&quot;Anchor link for: withiikhidaebb-hard-constraint&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;อีกฝั่งหนึ่งคือแนวคิดแบบ Hard constraint ซึ่งต่างจากแบบแรกพอสมควร เพราะกติกาไม่ได้อยู่แค่ในหัวคนหรือในเอกสารอีกต่อไป แต่ถูกฝังไว้ในระบบตั้งแต่ต้น ใครจะเข้าถึง Secret ได้ ต้องผ่านอะไรบ้าง ระบบเป็นคนตัดสิน ไม่ใช่คนเลือกเอง ข้อดีของวิธีนี้คือ ต่อให้ระบบโตขึ้น มีคนเข้ามาเกี่ยวข้องมากขึ้น หรือมีขั้นตอนซับซ้อนขึ้นแค่ไหน กติกาก็ยังถูกบังคับใช้อย่างสม่ำเสมอ แต่แน่นอนว่ามันแลกมาด้วยต้นทุนที่สูงขึ้น ทั้งเรื่องเวลา การออกแบบ และการลงทุนกับระบบตั้งแต่แรก ซึ่งตรงนี้แหละครับ ที่หลายองค์กรต้องตัดสินใจให้ชัด ว่าจะยอมจ่ายต้นทุนตรงไหน เพื่อแลกกับความเสี่ยงที่ลดลงในระยะยาว&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aimaichaekhechphaaa-secret&quot;&gt;ไม่ใช่แค่เฉพาะ Secret&lt;a class=&quot;zola-anchor&quot; href=&quot;#aimaichaekhechphaaa-secret&quot; aria-label=&quot;Anchor link for: aimaichaekhechphaaa-secret&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จริงๆ แล้วแนวคิดนี้ไม่ได้หยุดอยู่แค่เรื่อง Secret เลยครับ ถ้าลองมองดีๆ จะเห็นว่ากระบวนการอีกหลายอย่างในองค์กรก็หน้าตาไม่ต่างกัน ไม่ว่าจะเป็นขั้นตอนการ deploy การอนุมัติสิทธิ์ การเข้าถึงระบบ หรือแม้แต่การแก้ไข production หลายที่ยังคงอาศัยความระมัดระวังของคนเป็นหลัก มีข้อตกลง มีแนวปฏิบัติ แต่ระบบเองไม่ได้ช่วยบังคับหรือช่วยป้องกันมากนัก ซึ่งพอทุกอย่างเริ่มเร็วขึ้น งานมากขึ้น และคนมากขึ้น ช่องว่างเล็กๆ เหล่านี้ก็เริ่มกลายเป็นความเสี่ยงที่มองไม่เห็นครับ&lt;&#x2F;p&gt;
&lt;p&gt;ตรงนี้แหละครับที่ผมมองว่า DevOps เข้ามามีบทบาทสำคัญ ไม่ใช่ในฐานะคนดูแลเครื่องมือ หรือคนเขียน pipeline แต่เป็นคนที่คอยออกแบบระบบให้ความเร็วกับความปลอดภัยเดินไปด้วยกันได้ แทนที่จะฝากความหวังไว้กับความจำหรือความระวังของคน DevOps จะพยายามย้ายกติกาเหล่านั้นเข้าไปอยู่ในระบบ ทำให้สิ่งที่ควรทำ กลายเป็นสิ่งที่ทำได้ง่าย และสิ่งที่ไม่ควรทำ กลายเป็นสิ่งที่ทำได้ยากหรือทำไม่ได้เลย ซึ่งสุดท้ายแล้ว มันช่วยลดความเสี่ยงที่เกิดจากความผิดพลาดเล็กๆ น้อยๆ ที่หลีกเลี่ยงไม่ได้ของมนุษย์ครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sngthaay&quot;&gt;ส่งท้าย&lt;a class=&quot;zola-anchor&quot; href=&quot;#sngthaay&quot; aria-label=&quot;Anchor link for: sngthaay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;สุดท้ายแล้ว ภาพกุญแจที่เสียบคาไว้อยู่หน้าร้านในวันนั้น มันไม่ได้เป็นเรื่องของความสะเพร่า หรือความไม่รอบคอบของใครเป็นพิเศษ แต่มันสะท้อนให้เห็นว่า เรากำลังออกแบบระบบให้ต้องพึ่งพามนุษย์มากแค่ไหน ในโลกของซอฟต์แวร์ก็ไม่ต่างกันครับ ยิ่งระบบโต ยิ่งเร็ว และยิ่งมีคนเกี่ยวข้องมากเท่าไหร่ ความหวังดีหรือความระวังของคนก็ยิ่งไม่พอ สิ่งที่ช่วยได้จริงๆ คือการออกแบบระบบที่คิดเผื่อความผิดพลาดเอาไว้ตั้งแต่ต้น และปล่อยให้ระบบทำหน้าที่ดูแลความปลอดภัยแทนเราให้มากที่สุด เท่านี้เองครับ ที่ทำให้ความเร็วกับความปลอดภัยอยู่ด้วยกันได้โดยไม่ต้องเลือกอย่างใดอย่างหนึ่ง&lt;&#x2F;p&gt;
&lt;p&gt;สำหรับบทความนี้ ผมขอเล่าไว้ประมาณนี้ก่อนนะครับ ส่วนรายละเอียด Workshop เดี๋ยวไว้เขียนแยกอีก blog ละกัน ถ้ามีเวลาจะมาเล่าให้ฟังแบบค่อยเป็นค่อยไป ตั้งแต่แนวคิด ไปจนถึงการลงมือทำจริง เพื่อให้เห็นภาพชัดๆ มากขึ้น รวมถึงจะเอา record ตอนที่ไปพูดบนเวทีกลับมาแปะไว้ด้วย ตอนนี้ขอฝาก slide กับ code ที่ใช้ในงานไว้ก่อน เผื่อใครอยากลองเปิดดู ลองไล่ตาม หรือจะเอาไปคุยกับน้อง AI ต่อเล่นๆ ระหว่างรอ ก็ถือว่าเป็นจุดเริ่มต้นที่ดีแล้วครับ :)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.google.com&#x2F;presentation&#x2F;d&#x2F;1BWcvEZYCFBLRNOGvDJ9YNefIBRW2DncbdS4cXvOaaBQ&#x2F;edit?usp=sharing&quot;&gt;Slide &quot;TypeScript for Confident Deploys and Safe Secrets | Northern Tech on the Rock 2026&quot;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;ts-confident-deploy-and-secret&quot;&gt;Code ตัวอย่างใน Workshop บน GitHub&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;ts-confident-deploy-and-secret-speaker&quot;&gt;Speaker Repo&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>รีวิวปี 2025 กับการปล่อยให้ทีม DevOps ตัดสินใจได้เอง และเป็นทีมที่ flat มากขึ้น</title>
		<published>2025-12-21T00:00:00+00:00</published>
		<updated>2025-12-21T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/review-2025-devops-team-reflection-flat-team/" type="text/html"/>
		<id>https://thadaw.com/posts/review-2025-devops-team-reflection-flat-team/</id>
		<content type="html">&lt;p&gt;ตอนนี้ก็ใกล้จะจบปีแล้ว พอมองย้อนกลับไป ผมรู้สึกว่าปีนี้เป็นปีแห่งการเปลี่ยนแปลงจริงๆ ไม่ใช่แค่ในแง่ของเทคโนโลยีหรือระบบที่เราใช้อยู่ แต่เป็นการเปลี่ยนวิธีคิดและวิธีทำงานของทั้งทีม การเขียน reflection ครั้งนี้ ผมหวังว่าจะเป็นประโยชน์กับใครหลายคน โดยเฉพาะคนที่กำลังดูแลทีมอยู่ เพราะมันเป็นเรื่องของการค่อยๆ ปรับทีมให้ flat ขึ้น และผลลัพธ์ที่ได้ กลับดีกว่าที่ผมคาดไว้มาก&lt;&#x2F;p&gt;
&lt;h2 id=&quot;emuue-khwaamlae-iiydkh-ngphm-klaayepn-bottleneck-kh-ngthiim&quot;&gt;เมื่อความละเอียดของผม กลายเป็น bottleneck ของทีม&lt;a class=&quot;zola-anchor&quot; href=&quot;#emuue-khwaamlae-iiydkh-ngphm-klaayepn-bottleneck-kh-ngthiim&quot; aria-label=&quot;Anchor link for: emuue-khwaamlae-iiydkh-ngphm-klaayepn-bottleneck-kh-ngthiim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ตั้งแต่ไหนแต่ไรมา ผมเป็นคนที่มั่นใจในตัวเองมาก เพราะอาจจะทำอะไรหลายๆ อย่างด้วยตัวเองมาตลอด ก่อนมาเป็น DevOps Engineer ผมก็เขียนโปรแกรมมาเยอะ ซนมาเยอะ มันก็เลยทำให้ผมเป็นคน perfectionist โดยไม่รู้ตัว&lt;&#x2F;p&gt;
&lt;p&gt;ตอนที่ยังเป็น DevOps Engineer ช่วงนั้นผมไว้ใจตัวเองมาก โดยเฉพาะในเรื่องรายละเอียดของงาน ไม่ว่าจะเป็นการออกแบบระบบ โครงสร้างของ infrastructure หรือผลกระทบระยะยาว ทุกอย่างต้อง “ดีพอ” ก่อนถึงจะปล่อยไปได้ ความรู้สึกตอนนั้นคือ ถ้าผมเป็นคนทำเอง ผมจะคุมคุณภาพได้ และนั่นคือสิ่งที่ทำให้ผมมั่นใจว่างานจะไม่พัง&lt;&#x2F;p&gt;
&lt;p&gt;อย่างไรก็ตาม คำว่า &lt;strong&gt;perfectionist&lt;&#x2F;strong&gt; ในแบบของผม ไม่ได้หมายความว่าผมอยากทำทุกอย่างให้ใหญ่หรือเกินความจำเป็น เวลาทำงาน ผมเริ่มจากคำถามว่า &lt;u&gt;ทำไมเราต้องทำสิ่งนี้ และปัญหาที่แท้จริงคืออะไร&lt;&#x2F;u&gt; ก่อนจะคิดถึงวิธีแก้หรือเครื่องมือที่ใช้ ผมให้ความสำคัญกับบริบทและข้อจำกัดรอบตัวเสมอ ไม่ว่าจะเป็นเวลา ทีม หรือผลกระทบต่อระบบอื่นๆ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;review-2025-devops-team-reflection-flat-team&#x2F;01-perfectionist.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ความเป็น perfectionist ของผมจึงไม่ได้อยู่ที่การขยาย scope งาน แต่เป็นเรื่องของคุณภาพและการออกแบบ งานอาจเริ่มจากจุดเล็กๆ ได้ แต่โครงสร้างต้องไม่ปิดทางการเติบโตในอนาคต ผมมักคิดเสมอว่า &lt;em&gt;ถ้าวันหนึ่งระบบนี้ต้อง scale ขึ้น จะยังไปต่อได้หรือไม่ และการตัดสินใจวันนี้ จะกลายเป็นภาระของทีมในวันข้างหน้าหรือเปล่า&lt;&#x2F;em&gt; ความละเอียดในจุดนี้เองที่ทำให้ผมรู้สึกสบายใจเมื่อปล่อยงานออกไป&lt;&#x2F;p&gt;
&lt;p&gt;ในช่วงที่ผมยังทำงานคนเดียว หรือทีมยังเล็ก วิธีคิดแบบนี้ช่วยให้งานออกมามั่นคงและรับมือกับการเปลี่ยนแปลงได้ดี แต่ผมก็เริ่มตระหนักทีหลังว่า สิ่งที่เคยเป็นจุดแข็งของผม อาจกลายเป็นข้อจำกัดของทีม เมื่อคนที่ต้องตัดสินใจทุกอย่างยังเป็นคนเดิม&lt;&#x2F;p&gt;
&lt;p&gt;สิ่งที่เป็นผลลัพธ์ก็คือ ระบบ Platform หลังบ้านที่ดูแลเป็น Automation ทั้งส่วนของ infra และ Pipeline ต่างๆ ถูกสร้างขึ้นมา และสามารถต่อยอดมาได้เรื่อยๆ และแทบไม่มีส่วนไหนที่ต้องมานั่งรื้อทิ้งใหม่ เผื่อใครนึกภาพไม่ออก พอดีผมเพิ่งได้รับเชิญจากพี่รูฟไปพูดในงาน Platform Engineering Meetup ที่ ODDS ผมเลยวิดิโอมาให้ดูเผื่อจะช่วยให้เห็นภาพมากขึ้นครับ&lt;&#x2F;p&gt;
&lt;div class=&quot;youtube-embed &quot;&gt;
    &lt;iframe
        src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;Rb7HkHZa4MU&quot;
        frameborder=&quot;0&quot;
        allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;
        allowfullscreen
        title=&quot;ผมไปแบ่งปันประสบการณ์การสร้าง Platform จากศูนย์ ที่ ODDS ในงาน Platform Engineering Meetup เมื่อวันที่ 2 ส.ค. 2568 ที่ผ่านมา&quot;&gt;
    &lt;&#x2F;iframe&gt;

    
    &lt;div class=&quot;youtube-caption&quot;&gt;
        ผมไปแบ่งปันประสบการณ์การสร้าง Platform จากศูนย์ ที่ ODDS ในงาน Platform Engineering Meetup เมื่อวันที่ 2 ส.ค. 2568 ที่ผ่านมา
    &lt;&#x2F;div&gt;
    
&lt;&#x2F;div&gt;&lt;h2 id=&quot;israkh-ng-devops-aelatnthunthiim-ngaimehn&quot;&gt;อิสระของ DevOps และต้นทุนที่มองไม่เห็น&lt;a class=&quot;zola-anchor&quot; href=&quot;#israkh-ng-devops-aelatnthunthiim-ngaimehn&quot; aria-label=&quot;Anchor link for: israkh-ng-devops-aelatnthunthiim-ngaimehn&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ต้องบอกก่อนว่า การที่ทีม DevOps ของผมทำทุกอย่างเอง ไม่ใช่สิ่งที่เกิดขึ้นโดยบังเอิญ แต่เป็นการตัดสินใจของผมเองตั้งแต่ต้น งานหลายอย่างในโลกของ DevOps เข้าถึงยาก อธิบายยาก และมองจากภายนอกแทบไม่เห็นคุณค่า สิ่งที่คนส่วนใหญ่มองเห็นมักเป็นแค่ผลลัพธ์ปลายทาง เช่น deploy เร็วขึ้น ระบบเสถียรขึ้น หรือ workflow สะดวกขึ้น แต่เบื้องหลังของสิ่งเหล่านี้เต็มไปด้วยรายละเอียด การออกแบบ และการตัดสินใจที่ซับซ้อน&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;ในช่วงแรก ผมเลือกที่จะรับมันไว้เอง&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;review-2025-devops-team-reflection-flat-team&#x2F;02-stacking.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ตอนที่ผมยังทำงานคนเดียว หรือทีมยังเล็ก วิธีนี้ทำให้ทุกอย่างเดินได้เร็ว และคุณภาพของงานออกมาค่อนข้างนิ่ง แต่เมื่อทีมเริ่มมีคนเพิ่มขึ้น สิ่งที่เคยเป็นจุดแข็ง ก็เริ่มแสดงผลข้างเคียงออกมาชัดขึ้นเรื่อยๆ แม้จะมีทีมแล้ว แต่การตัดสินใจสำคัญหลายอย่างยังคงวนกลับมาที่ผม ไม่ว่าจะเป็นเรื่องการออกแบบ การเลือกแนวทาง หรือการปล่อยงาน ทุกอย่างต้องผ่านสายตาผมก่อนเสมอ โดยไม่รู้ตัว ผมกลายเป็นทั้งคนออกแบบ คนตรวจคุณภาพ และคนให้คำตอบสุดท้ายในเวลาเดียวกัน&lt;&#x2F;p&gt;
&lt;p&gt;ในขณะที่ทีม developer โดยทั่วไปจะมี BA, SA และ PM คอยช่วยจัดการ requirement วางแผนงาน และช่วยคิดเรื่อง design ที่ซับซ้อน &lt;strong&gt;DevOps team ของผมกลับต้องทำทุกอย่างเอง ตั้งแต่รับโจทย์ที่ยังไม่ชัด แกะ requirement ออกมา วิเคราะห์ผลกระทบ ออกแบบระบบ วางแผน sprint ไปจนถึงลงมือทำจริง&lt;&#x2F;strong&gt; โมเดลการทำงานแบบนี้ให้อิสระกับทีมสูงมาก และเปิดโอกาสให้ DevOps Engineer ได้เห็นภาพระบบแบบ end-to-end แต่ในขณะเดียวกัน ความรับผิดชอบก็สูงขึ้นอย่างหลีกเลี่ยงไม่ได้&lt;&#x2F;p&gt;
&lt;p&gt;ช่วงนั้นผมยังรู้สึกว่านี่คือสิ่งที่ควรทำ และเป็นหน้าที่ของผมในฐานะ DevOps Team Lead ที่ต้องช่วยดูแลคุณภาพของงานให้ดีที่สุด แต่สิ่งที่เริ่มชัดขึ้นเรื่อยๆ คือ งานจำนวนมากไม่ได้ช้าเพราะทีมทำไม่ได้ หากแต่ช้าเพราะต้องรอการตัดสินใจจากผม และในหลายครั้ง ผมเองก็เริ่มใช้เวลาส่วนใหญ่ไปกับการ review และ approve มากกว่าการคิดภาพรวมในระดับที่ควรจะเป็น&lt;&#x2F;p&gt;
&lt;p&gt;ผมไม่ได้รู้สึกว่างานกำลังพัง หรือทีมกำลังไปต่อไม่ได้ ความจริงคือทุกอย่างยังเดินได้ดี เพียงแต่ผมเริ่มรู้สึกว่าพลังที่ใช้ไปในแต่ละวัน เริ่มไม่สมดุลกับสิ่งที่ผมควรโฟกัสในบทบาทนี้มากขึ้นเรื่อยๆ และที่สำคัญคือ ผมเริ่มเห็นว่าหลายอย่างยังคงขึ้นอยู่กับผมมากเกินไป โดยไม่รู้ตัว ผมกลายเป็น single point of failure ทั้งในเชิงการตัดสินใจและการขับเคลื่อนงาน กล่าวคือ ถ้าผมช้า งานจำนวนหนึ่งก็จะช้าตามไปด้วย&lt;&#x2F;p&gt;
&lt;p&gt;ในฐานะคนที่ออกแบบระบบ ผมคุ้นเคยกับแนวคิดนี้ดี ระบบที่ดีไม่ควรผูกความสำคัญไว้กับองค์ประกอบเดียว และเมื่อหันกลับมามองการทำงานภายในทีม ผมก็เริ่มรู้สึกไม่ต่างกัน โครงสร้างการทำงานที่ยังต้องรอผมอยู่ตลอด อาจจะยังใช้งานได้ในวันนี้ แต่ไม่ใช่สิ่งที่ผมอยากออกแบบให้ทีมต้องพึ่งพาในระยะยาว&lt;&#x2F;p&gt;
&lt;p&gt;ตอนนั้นผมยังไม่รู้คำตอบที่ชัดเจนว่าควรแก้ปัญหานี้อย่างไร รู้แค่ว่าถ้ายังทำงานในรูปแบบเดิมต่อไป ไม่ใช่แค่ทีมที่จะเหนื่อย แต่ตัวผมเองก็คงไปต่อได้ไม่ไกลเช่นกัน&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cchudthiit-ngy-mrabwaa-thaaaimpl-y-thiimcchaaipt-aimaid&quot;&gt;จุดที่ต้องยอมรับว่า ถ้าไม่ปล่อย ทีมจะไปต่อไม่ได้&lt;a class=&quot;zola-anchor&quot; href=&quot;#cchudthiit-ngy-mrabwaa-thaaaimpl-y-thiimcchaaipt-aimaid&quot; aria-label=&quot;Anchor link for: cchudthiit-ngy-mrabwaa-thaaaimpl-y-thiimcchaaipt-aimaid&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ต่อมาผมเริ่มยอมรับอย่างจริงจังว่า ปัญหาไม่ได้อยู่ที่ความสามารถของทีม หรือคุณภาพของระบบ แต่เป็นโครงสร้างการทำงานที่ผูกทุกการตัดสินใจไว้กับคนคนเดียว ความเหนื่อยสะสมที่เพิ่มขึ้นเรื่อยๆ เป็นสัญญาณชัดว่าผมกำลังแบกมากเกินไป และวิธีทำงานแบบเดิมไม่ยั่งยืนอีกต่อไป&lt;&#x2F;p&gt;
&lt;p&gt;คำแนะนำที่ผมได้รับจากหัวหน้าในตอนนั้นไม่ได้ซับซ้อนอะไร &lt;strong&gt;เขาเพียงบอกให้ผมลองปล่อย ลองทำทีมให้แบนลง และเลิกเป็นจุด approve ของทุก decision&lt;&#x2F;strong&gt; ฟังดูง่าย แต่สำหรับคนที่เคยควบคุมคุณภาพทุกอย่างด้วยตัวเอง มันไม่ใช่เรื่องเล็กเลย การปล่อยในที่นี้ไม่ได้หมายความว่าปล่อยปละละเลย แต่คือการยอมรับว่าคุณภาพอาจไม่สมบูรณ์แบบเท่าที่ผมคุ้นเคย และเปิดโอกาสให้ทีมได้เรียนรู้จากการตัดสินใจของตัวเอง&lt;&#x2F;p&gt;
&lt;p&gt;ในตอนนั้นผมยังไม่แน่ใจว่าวิธีนี้จะเวิร์กจริงหรือไม่ รู้แค่ว่าถ้ายังทำงานในรูปแบบเดิมต่อไป ต่อให้ระบบยังรันอยู่ดี ทีมอาจจะไปต่อไม่ได้ และที่สำคัญ ตัวผมเองก็คงไม่สามารถแบกทุกอย่างไว้ได้นานกว่านี้แล้ว&lt;&#x2F;p&gt;
&lt;h2 id=&quot;chwngthiiyaakthiisud-khuue-kaarwaangaicchkhn-uuen&quot;&gt;ช่วงที่ยากที่สุด คือการวางใจคนอื่น&lt;a class=&quot;zola-anchor&quot; href=&quot;#chwngthiiyaakthiisud-khuue-kaarwaangaicchkhn-uuen&quot; aria-label=&quot;Anchor link for: chwngthiiyaakthiisud-khuue-kaarwaangaicchkhn-uuen&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลังจากตัดสินใจว่าจะลองปล่อย และทำทีมให้แบนลงจริงๆ สิ่งที่ยากที่สุดสำหรับผม ไม่ใช่การปรับ process หรือเปลี่ยนวิธีทำงาน แต่คือการจัดการกับตัวเอง ความรู้สึกที่เคยมั่นใจว่า &lt;em&gt;“ถ้าผมทำเอง ทุกอย่างจะปลอดภัยกว่า”&lt;&#x2F;em&gt; ยังอยู่ครบ และมันไม่ได้หายไปเพียงเพราะผมตัดสินใจเปลี่ยนบทบาท&lt;&#x2F;p&gt;
&lt;p&gt;ในช่วงแรก ผมต้องฝืนตัวเองอย่างมากที่จะไม่เข้าไปแก้ ไม่เข้าไปชี้นำทุกจุด และไม่เข้าไปตัดสินใจแทนทีม หลายครั้งผมเห็นสิ่งที่ถ้าเป็นผม ผมอาจจะทำต่างออกไป และต้องยอมรับความไม่สบายใจนั้นไว้ให้ได้ การวางใจคนอื่นในที่นี้ ไม่ใช่การเชื่อว่าทุกการตัดสินใจจะถูกต้อง แต่คือการยอมรับว่าความผิดพลาดเป็นส่วนหนึ่งของการเรียนรู้&lt;&#x2F;p&gt;
&lt;p&gt;สิ่งที่ผมค่อยๆ เรียนรู้คือ &lt;strong&gt;หน้าที่ของผมไม่ใช่การทำให้ทุก decision ออกมาสมบูรณ์แบบ แต่คือการสร้างพื้นที่ที่ทีมกล้าตัดสินใจ และกล้ารับผลของการตัดสินใจนั้น&lt;&#x2F;strong&gt; ผมเริ่มเปลี่ยนจากการให้คำตอบ เป็นการตั้งคำถาม จากการบอกว่าควรทำอย่างไร เป็นการชวนคิดว่ามีทางเลือกอะไรบ้าง และแต่ละทางเลือกมีผลกระทบอย่างไร&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;review-2025-devops-team-reflection-flat-team&#x2F;03-releasing.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ช่วงเวลานี้ทำให้ผมเห็นชัดว่า ความไว้วางใจไม่ใช่สิ่งที่เกิดขึ้นจากคำพูดหรือโครงสร้างทีม แต่เกิดจากการกระทำซ้ำๆ การไม่เข้าไปแทรกแซงโดยไม่จำเป็น การยอมรับว่าคุณภาพอาจยังไม่เท่าที่ผมเคยทำเอง และการยืนอยู่ข้างทีม แม้ในวันที่การตัดสินใจนั้นไม่ออกมาสมบูรณ์แบบนัก&lt;&#x2F;p&gt;
&lt;p&gt;ผมไม่กล้าบอกว่าช่วงนี้เป็นช่วงที่สบาย เพราะมันไม่ใช่ แต่เป็นช่วงที่ทำให้ผมเข้าใจความหมายของคำว่า leadership ชัดขึ้นกว่าที่เคย การวางใจคนอื่นไม่ใช่การปล่อยมือทั้งหมด แต่คือการเลือกที่จะไม่จับทุกอย่างไว้แน่นเหมือนเดิม และนั่นอาจเป็นทักษะที่ยากที่สุดที่ผมต้องเรียนรู้ในปีนี้&lt;&#x2F;p&gt;
&lt;h2 id=&quot;withiithamngaanaebb-flat-thiikh-y-epnruupepnraang&quot;&gt;วิธีทำงานแบบ flat ที่ค่อยๆ เป็นรูปเป็นร่าง&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiithamngaanaebb-flat-thiikh-y-epnruupepnraang&quot; aria-label=&quot;Anchor link for: withiithamngaanaebb-flat-thiikh-y-epnruupepnraang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลังจากผ่านช่วงที่ต้องปรับใจและเรียนรู้ที่จะวางใจคนอื่น วิธีทำงานแบบ flat ไม่ได้เกิดขึ้นจากการเปลี่ยนโครงสร้างทีมในทันที แต่มันค่อยๆ เป็นรูปเป็นร่างจากการปรับพฤติกรรมเล็กๆ ในแต่ละวัน มากกว่าการออกกฎหรือประกาศวิธีทำงานใหม่อย่างเป็นทางการ&lt;&#x2F;p&gt;
&lt;p&gt;สิ่งแรกที่ผมเริ่มทำคือการถอยตัวเองออกจาก flow งานประจำวัน ผมเลิกเป็นคน approve ทุกอย่าง และพยายามไม่เป็นจุดศูนย์กลางของการตัดสินใจ DevOps Engineer แต่ละคนเริ่มรับโจทย์เอง ตั้งแต่การไปคุยหา requirement วิเคราะห์ปัญหา ออกแบบแนวทาง ลงมือทำ ทดสอบ และ deploy ให้จบในตัวเอง โดยใช้ peer-review ภายในทีมเป็นกลไกหลักในการรักษาคุณภาพ&lt;&#x2F;p&gt;
&lt;p&gt;การตัดสินใจหลายอย่างจึงเริ่มเกิดใกล้กับปัญหามากขึ้น คนที่ลงมือทำเป็นคนตัดสินใจ และรับผิดชอบผลลัพธ์ของงานนั้นโดยตรง &lt;strong&gt;บทบาทของผมเปลี่ยนไปเป็นการเข้ามาช่วยในจุดที่ซับซ้อน หรือมีผลกระทบในระดับที่ต้องการมุมมองเพิ่ม&lt;&#x2F;strong&gt; ไม่ใช่เพื่อให้คำตอบสุดท้าย แต่เพื่อช่วยตั้งคำถามและทำให้บริบทของการตัดสินใจชัดขึ้น&lt;&#x2F;p&gt;
&lt;p&gt;ในส่วนของการวางแผนงาน ผมยังคงเป็นคนออกแบบ sprint อยู่ เพราะต้องคอย balance ระหว่างงานจาก product, developer และ roadmap ภายในของทีม DevOps เอง แต่ภายใน sprint นั้น ทีมเป็นคนจัดการรายละเอียดทั้งหมด ตั้งแต่วิธีทำ การแบ่งงาน ไปจนถึงการผลักงานให้เสร็จ โดยไม่ต้องรอการควบคุมจากผมเหมือนเดิม&lt;&#x2F;p&gt;
&lt;p&gt;วิธีทำงานแบบ flat ในแบบของผมจึงไม่ได้หมายถึงการปล่อยทุกอย่างออกจากมือ แต่คือการเลือกถือเฉพาะสิ่งที่จำเป็นจริงๆ และปล่อยให้ทีมถือ ownership ของงานในส่วนที่พวกเขาพร้อมจะรับผิดชอบ วิธีนี้ค่อยๆ ลดการพึ่งพาคนคนเดียว และทำให้ระบบการทำงานเดินต่อไปได้ แม้บทบาทของผมจะไม่ได้อยู่ในทุกขั้นตอนเหมือนที่ผ่านมา&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bthbaathaihmkh-ngphmainthaana-devops-team-lead&quot;&gt;บทบาทใหม่ของผมในฐานะ DevOps Team Lead&lt;a class=&quot;zola-anchor&quot; href=&quot;#bthbaathaihmkh-ngphmainthaana-devops-team-lead&quot; aria-label=&quot;Anchor link for: bthbaathaihmkh-ngphmainthaana-devops-team-lead&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เมื่อวิธีทำงานแบบ flat เริ่มนิ่งขึ้น บทบาทของผมในฐานะ DevOps Team Lead ก็เปลี่ยนไปอย่างชัดเจน จากคนที่เคยอยู่ในแทบทุกขั้นตอนของงาน กลายเป็นคนที่เลือกเข้าไปอยู่เฉพาะในจุดที่ทีมต้องการจริงๆ ไม่ใช่เพราะผมอยากถอยออกมา แต่เพราะบทบาทที่ทีมต้องการจากผม เปลี่ยนไปตามบริบทขององค์กร&lt;&#x2F;p&gt;
&lt;p&gt;ก่อนหน้านี้ ตอนที่บริษัทยังเล็ก ทีม Dev, DevOps, Product, Customer-facing รวมถึงทีม IT Admin ทำงานใกล้ชิดกันมาก หลายปัญหาแก้ได้ด้วยการคุยกันตรงๆ หรือส่งข้อความใน Slack ไม่กี่บรรทัด ผมสามารถเห็นภาพรวมของระบบได้แทบทั้งหมด และการทำงานแบบ proactive ก็เป็นเรื่องที่ค่อนข้างเป็นธรรมชาติ&lt;&#x2F;p&gt;
&lt;p&gt;แต่เมื่อองค์กรถูกซื้อโดยบริษัทที่ใหญ่ขึ้น โครงสร้างทุกอย่างเริ่มซับซ้อนขึ้น ทีมกระจายตัว การสื่อสารกลายเป็นอีเมล การประชุมข้าม timezone และการทำงานที่กลางวันกลางคืนไม่ตรงกัน บริบทที่เคยเห็นชัด กลับต้องใช้ความพยายามมากขึ้นกว่าจะปะติดปะต่อได้ และการทำงานเชิงรุกที่ผมถนัด ก็ยิ่งทำได้ยากขึ้นเรื่อยๆ หากผมยังต้องอยู่ใน flow งานประจำวันเหมือนเดิม&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;review-2025-devops-team-reflection-flat-team&#x2F;04-directing.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;งานหลักของผมในช่วงนี้จึงไม่ใช่การ approve หรือสั่งการ แต่เป็นการ consult ในปัญหาที่ซับซ้อนหรือมีผลกระทบสูง โดยเฉพาะเรื่องที่ต้องอาศัยประสบการณ์เชิงระบบ หรือการตัดสินใจที่มีผลระยะยาว &lt;em&gt;โดยพยายามไม่เข้าไปให้คำตอบสำเร็จรูป แต่ช่วยตั้งคำถาม ช่วยชี้ให้เห็น trade-off และช่วยเติม context ที่ทีมอาจยังมองไม่ครบ&lt;&#x2F;em&gt; เพื่อให้การตัดสินใจนั้นเกิดใกล้กับจุดที่ลงมือทำมากที่สุด&lt;&#x2F;p&gt;
&lt;p&gt;อีกส่วนหนึ่งของบทบาทที่สำคัญมาก คือการทำงานกับทีม USA และทีม product ในระดับที่สูงขึ้น เรื่องเหล่านี้มักไม่ใช่ task รายวัน แต่เป็นการสื่อสารทิศทาง ความคาดหวัง และข้อจำกัดของระบบ &lt;strong&gt;ผมทำหน้าที่เป็นตัวกลางในการแปลความต้องการเชิงธุรกิจ ให้กลายเป็นกรอบที่ทีม DevOps สามารถนำไปตัดสินใจต่อได้เอง โดยไม่ต้องรอคำสั่งจากผมทุกครั้ง&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ในขณะเดียวกัน ผมมองว่าหน้าที่ของ DevOps Team Lead คือ&lt;u&gt;การปกป้องทีมจาก noise ที่ไม่จำเป็น ไม่ใช่ทุก requirement ที่เข้ามาจะพร้อม หรือควรถูกทำทันที&lt;&#x2F;u&gt; การช่วยกรอง ชะลอ และจัดลำดับความสำคัญ คือส่วนหนึ่งของการทำให้ทีมมีสมาธิกับสิ่งที่สำคัญจริงๆ และไม่ต้องรับแรงกดดันทั้งหมดโดยตรง&lt;&#x2F;p&gt;
&lt;p&gt;บทบาทใหม่นี้อาจดูเหมือนผมถอยออกมาจากงาน แต่ในความเป็นจริง ผมกลับต้องใช้พลังมากขึ้นในอีกแบบหนึ่ง แทนที่จะใช้พลังไปกับการแก้ปัญหาเฉพาะหน้า ผมต้องใช้พลังไปกับการคิดเชิงระบบ การสื่อสารข้ามทีม และการมองความเสี่ยงล่วงหน้าในบริบทขององค์กรที่ใหญ่ขึ้น&lt;&#x2F;p&gt;
&lt;p&gt;สิ่งที่ผมเริ่มเห็นชัดคือ เมื่อผมเลิกเป็นศูนย์กลางของทุกอย่าง ทีมกลับทำงานได้คล่องขึ้น และ paradox ที่เกิดขึ้นคือ ผมกลับมีพื้นที่และสมาธิมากพอที่จะทำงานแบบ proactive ได้ดีกว่าเดิม ทั้งกับทีม DevOps เอง และกับทีม Product, Customer-facing รวมถึง IT Admin ที่อยู่ไกลตัวมากขึ้น ผมเองก็ยังไม่แน่ใจว่าวิธีนี้คือคำตอบที่ดีที่สุดหรือไม่ แต่สิ่งที่เห็นชัดคือ ทีมเริ่มเดินงานได้ด้วยตัวเองมากขึ้นกว่าที่เคย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sprint-aela-roadmap-thiithiimt-ng-kaebbe-ng&quot;&gt;Sprint และ Roadmap ที่ทีมต้องออกแบบเอง&lt;a class=&quot;zola-anchor&quot; href=&quot;#sprint-aela-roadmap-thiithiimt-ng-kaebbe-ng&quot; aria-label=&quot;Anchor link for: sprint-aela-roadmap-thiithiimt-ng-kaebbe-ng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เมื่อผมถอยออกมาจากการตัดสินใจในรายละเอียด งานหนึ่งที่ผมยังคงต้องดูแลอยู่คือการออกแบบ sprint ของทีม ไม่ใช่เพื่อแจก task หรือควบคุมการทำงานรายวัน แต่เพื่อจัดกรอบและจังหวะของงานให้สอดคล้องกับบริบททั้งหมดที่ทีมต้องรับมืออยู่ในช่วงนั้น&lt;&#x2F;p&gt;
&lt;p&gt;ทีม DevOps ของเราไม่ได้ทำงานจาก requirement ที่ถูกส่งมาอย่างเดียว &lt;strong&gt;ยังมีงานอีกจำนวนมากที่ไม่มีใครส่งมาเป็น ticket ชัดเจน ไม่ว่าจะเป็นเรื่อง security, operation, cost optimization, platform foundation หรือการทดลองทำ R&amp;amp;D เพื่อเตรียมระบบสำหรับอนาคต&lt;&#x2F;strong&gt; งานเหล่านี้อาจยังไม่เร่งด่วนในวันนี้ แต่ถ้าไม่ถูกจัดการไว้ก่อน มันจะกลายเป็นภาระของทีมในวันข้างหน้าอย่างหลีกเลี่ยงไม่ได้&lt;&#x2F;p&gt;
&lt;p&gt;บทบาทของผมในส่วนนี้คือการช่วยมองภาพรวมและจัดลำดับความสำคัญ ให้ sprint มีพื้นที่สำหรับงานประเภทนี้อยู่เสมอ แต่เมื่อกรอบของ sprint ชัดแล้ว ทีมจะเป็นคนจัดการรายละเอียดทั้งหมดเอง ตั้งแต่วิธีทำ การตัดสินใจ ไปจนถึงการผลักงานให้เสร็จ โดยไม่ต้องรอการ approve จากผมเหมือนที่ผ่านมา&lt;&#x2F;p&gt;
&lt;p&gt;สิ่งที่เริ่มเห็นชัดคือ DevOps ไม่ได้ทำงานแบบรอโจทย์ หากช่วงไหนไม่มี requirement จาก product งานก็ยังเดินต่อได้ เพราะ roadmap ภายในของทีมยังคงถูกดูแลอยู่ตลอด Roadmap นี้ไม่ใช่เอกสารเพื่อรายงานใคร แต่เป็นเครื่องมือที่ช่วยให้ทีมรู้ว่า เรากำลังเลือกแบกอะไรไว้ และกำลังลดความเสี่ยงตรงไหนของระบบ&lt;&#x2F;p&gt;
&lt;p&gt;การที่ทีมต้องออกแบบและดูแล roadmap ของตัวเอง ทำให้ ownership ของงานชัดขึ้นมาก แต่ก็มาพร้อมกับความรับผิดชอบที่สูงขึ้นเช่นกัน งานของ DevOps มักไม่จบลงพร้อมกับระบบที่ยังทำงานได้ เพราะยังมีอีกหลายเรื่องที่ต้องจัดการ เพื่อไม่ให้มันกลายเป็นปัญหาในอนาคต&lt;&#x2F;p&gt;
&lt;h2 id=&quot;singthiiaidmaa-aelasingthiit-ngaelk&quot;&gt;สิ่งที่ได้มา และสิ่งที่ต้องแลก&lt;a class=&quot;zola-anchor&quot; href=&quot;#singthiiaidmaa-aelasingthiit-ngaelk&quot; aria-label=&quot;Anchor link for: singthiiaidmaa-aelasingthiit-ngaelk&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;สิ่งที่เห็นได้ชัดจากการปรับวิธีทำงานแบบ flat คือ ทีมเริ่มตัดสินใจได้เองมากขึ้น งานหลายอย่างไม่ต้องรอคำตอบจากผมเหมือนเดิม การตัดสินใจจำนวนมากเกิดขึ้นใกล้กับจุดที่ลงมือทำจริง และนั่นทำให้งานสามารถเดินต่อได้ แม้ผมจะไม่ได้อยู่ใน flow งานตลอดเวลา&lt;&#x2F;p&gt;
&lt;p&gt;ผลที่ตามมาคือ งานเริ่มไม่ผูกอยู่กับคนคนเดียว ระบบและกระบวนการต่างๆ ไม่ได้ขึ้นกับการตัดสินใจของผมเพียงอย่างเดียว ทีมรับผิดชอบงานของตัวเองตั้งแต่ต้นจนจบ และต้องรับผลของการตัดสินใจนั้นมากขึ้น ไม่ว่าจะออกมาดีหรือพลาดบ้างก็ตาม&lt;&#x2F;p&gt;
&lt;p&gt;แต่การเปลี่ยนผ่านแบบนี้ไม่ได้ราบรื่นทั้งหมด ช่วงแรกมี mistake เกิดขึ้นจริง มีบางการตัดสินใจที่ถ้าผมเป็นคนทำเอง อาจเลือกต่างออกไป คุณภาพของงานบางส่วนมีช่วงที่แกว่ง และทีมเองก็ต้องใช้เวลาในการปรับตัวกับความรับผิดชอบที่เพิ่มขึ้น&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;review-2025-devops-team-reflection-flat-team&#x2F;05-trying.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ในช่วงนั้น &lt;strong&gt;สิ่งที่ผมพยายามทำคือไม่รีบเข้าไปแก้ทุกอย่างทันที แต่เปิดพื้นที่ให้ทีมได้เรียนรู้จากความผิดพลาด ทีมสามารถล้ม หรือตกน้ำได้ แต่ไม่จมน้ำเพราะผมจะเป็นคนคอยดึงขึ้นมาเมื่อจำเป็น&lt;&#x2F;strong&gt; คอยปกป้องทีมจากแรงกดดันภายนอก และช่วยประสานงานกับฝ่ายอื่น เพื่อให้ทีมมีพื้นที่เรียนรู้และเดินต่อได้ โดยไม่ต้องรับแรงกระแทกทั้งหมดเพียงลำพัง&lt;&#x2F;p&gt;
&lt;p&gt;สิ่งที่ผมได้เรียนรู้จากประสบการณ์นี้คือ ความยั่งยืนของทีม DevOps ไม่ได้มาจากการตัดสินใจที่ถูกต้องทุกครั้ง แต่เกิดจากระบบการทำงานที่รองรับความผิดพลาดได้ และทีมที่สามารถเรียนรู้และปรับตัวจากมันได้เร็วพอ การยอมแลกความสบายใจในระยะสั้น จึงเป็นราคาที่หลีกเลี่ยงไม่ได้ หากต้องการให้ทีมและระบบเดินต่อได้ในระยะยาว&lt;&#x2F;p&gt;
&lt;h2 id=&quot;btheriiyneruue-ng-leadership-ainchiiwitcchring&quot;&gt;บทเรียนเรื่อง leadership ในชีวิตจริง&lt;a class=&quot;zola-anchor&quot; href=&quot;#btheriiyneruue-ng-leadership-ainchiiwitcchring&quot; aria-label=&quot;Anchor link for: btheriiyneruue-ng-leadership-ainchiiwitcchring&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ผมไม่คิดว่าบทเรียนเรื่อง leadership ที่ได้จากปีนี้ เป็นสิ่งใหม่ หรือเป็นความคิดที่ผมเพิ่งสร้างขึ้นมาเอง มันอาจจะถูกเขียนอยู่ใน tech blog หรือหนังสือเล่มไหนสักเล่มมานานแล้ว หรือผมอาจจะเคยเปิดอ่านผ่านๆ เมื่อนานมาแล้ว เพียงแต่ก่อนหน้านี้ ผมอาจจะยังไม่เคยเปิดไปเจอ หรือยังไม่อยู่ในจุดที่เข้าใจมันได้จริง&lt;&#x2F;p&gt;
&lt;p&gt;ตลอดเวลาที่ทำงาน ผมอ่านบทความกับหนังสือมามากพอสมควร หลายแนวคิดอ่านแล้วก็รู้สึกว่าเข้าใจ แต่ไม่ได้รู้สึกว่ามันเกี่ยวข้องกับตัวเองโดยตรง จนกระทั่งวันที่บทบาทของผมเปลี่ยน และปัญหาที่ต้องเจอไม่ใช่แค่เรื่องระบบ แต่เป็นเรื่องคนและความรับผิดชอบ แนวคิดเหล่านั้นถึงเริ่มมีความหมายขึ้นมา&lt;&#x2F;p&gt;
&lt;p&gt;สิ่งที่ผมเพิ่งได้เรียนรู้ คือ &lt;strong&gt;leadership ไม่ได้อยู่ที่การตัดสินใจให้ถูกที่สุดเสมอไป แต่อยู่ที่การยอมรับว่าการตัดสินใจบางอย่างจะไม่สมบูรณ์แบบ และหน้าที่ของผู้นำคือการอยู่กับผลลัพธ์นั้นไปพร้อมกับทีม การปล่อยให้ทีมตัดสินใจเอง&lt;&#x2F;strong&gt; ไม่ได้ทำให้บทบาทของผมลดลง แต่เปลี่ยนจากคนที่คุมทุกอย่าง มาเป็นคนที่ช่วยพยุงทีมในวันที่ผลลัพธ์ไม่เป็นอย่างที่หวัง&lt;&#x2F;p&gt;
&lt;p&gt;อีกอย่างหนึ่งที่ผมเพิ่งเข้าใจ คือการสร้างพื้นที่ที่ทีมสามารถผิดพลาดได้อย่างปลอดภัย ไม่ต่างจากการออกแบบระบบที่ต้องรองรับ failure การ defend ทีมเมื่อเกิดปัญหา ไม่ได้หมายความว่าทีมไม่มีความรับผิดชอบ แต่เป็นการให้เวลาทีมได้เรียนรู้ แก้ไข และเติบโต โดยไม่ถูกตัดสินเร็วเกินไป&lt;&#x2F;p&gt;
&lt;p&gt;ผมยังได้เรียนรู้ว่าการเป็นผู้นำที่ยั่งยืน เริ่มจากการรู้ขีดจำกัดของตัวเอง การยอมรับว่าเราไม่สามารถแบกทุกอย่างไว้ได้ และไม่ควรเป็นศูนย์กลางของทุกการตัดสินใจ สิ่งเหล่านี้อาจจะเคยถูกเขียนไว้ที่ไหนสักแห่งมาก่อนแล้ว เพียงแต่ปีนี้เป็นปีที่ผมได้มาเจอมันในชีวิตจริง&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าบทเรียนเหล่านี้จะมีคุณค่าอยู่บ้าง ผมหวังว่ามันอาจเป็นเหมือนหนังสืออีกเล่มหนึ่ง ที่คุณบังเอิญเปิดเจอในวันที่กำลังต้องการมันพอดี ไม่ใช่เพราะมันใหม่ แต่เพราะมันมาในเวลาที่เหมาะสม&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bthphisuucchnthiiphmaimaidwaangaephnaiw&quot;&gt;บทพิสูจน์ที่ผมไม่ได้วางแผนไว้&lt;a class=&quot;zola-anchor&quot; href=&quot;#bthphisuucchnthiiphmaimaidwaangaephnaiw&quot; aria-label=&quot;Anchor link for: bthphisuucchnthiiphmaimaidwaangaephnaiw&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;บทพิสูจน์ของการเปลี่ยนวิธีทำงานครั้งนี้ ไม่ได้มาจากการวัดผลหรือ retrospective ใดๆ แต่เกิดขึ้นจากสถานการณ์ที่ผมไม่ได้เตรียมตัวไว้เลย&lt;&#x2F;p&gt;
&lt;p&gt;ช่วงปลายเดือนพฤศจิกายนของปี เกิดน้ำท่วมครั้งใหญ่ที่สุดในรอบหลายสิบปีที่หาดใหญ่ ผมติดน้ำท่วมเกือบเป็นอาทิตย์ ไม่มีไฟฟ้า ไม่มีอินเทอร์เน็ต และไม่สามารถติดต่อทีมได้เลย ในสภาพแบบนั้น ผมไม่ได้ช่วยตัดสินใจ ไม่ได้ consult และไม่ได้ตามงานใดๆ ทั้งสิ้น ผมหายออกจากระบบไปอย่างสมบูรณ์&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;review-2025-devops-team-reflection-flat-team&#x2F;06-leaving.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;สิ่งที่เกิดขึ้นคือ ทีมยังทำงานต่อได้ตามปกติ งานไม่ได้หยุด ระบบยังเดิน และไม่มีเรื่องเร่งด่วนที่ต้องรอผมกลับมาแก้ไข&lt;&#x2F;strong&gt; สิ่งที่เคยกังวลว่า ถ้าผมไม่อยู่แล้วทุกอย่างจะชะงัก กลับไม่เกิดขึ้นจริง&lt;&#x2F;p&gt;
&lt;p&gt;ตอนที่ผมกลับมาออนไลน์อีกครั้ง ผมไม่ได้เห็นงานที่พัง หรือ backlog ที่ค้าง แต่เห็นทีมที่ยังเดินต่อได้ด้วยตัวเอง และรู้ว่าควรตัดสินใจอะไรโดยไม่ต้องรอคำตอบจากผม&lt;&#x2F;p&gt;
&lt;p&gt;ผมไม่ได้มองว่าสิ่งนี้เป็นความสำเร็จส่วนตัว แต่มันเป็นสัญญาณที่ชัดเจนที่สุดว่า การปล่อยบางอย่างออกจากมือก่อนหน้านี้ ทำให้ทีมแข็งแรงพอที่จะรับมือกับสถานการณ์ที่ไม่มีใครวางแผนไว้ได้จริงๆ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thaay-nklabaipb-ktawe-ngt-nyangepn-perfectionist-aid&quot;&gt;ถ้าย้อนกลับไปบอกตัวเองตอนยังเป็น perfectionist ได้&lt;a class=&quot;zola-anchor&quot; href=&quot;#thaay-nklabaipb-ktawe-ngt-nyangepn-perfectionist-aid&quot; aria-label=&quot;Anchor link for: thaay-nklabaipb-ktawe-ngt-nyangepn-perfectionist-aid&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ถ้าผมย้อนกลับไปคุยกับตัวเองในวันที่ยังเป็น DevOps Engineer ที่คุมทุกอย่างไว้คนเดียวได้ ผมคงไม่ได้บอกให้หยุดทำแบบนั้นทันที เพราะในตอนนั้น มันอาจเป็นวิธีที่ดีที่สุดเท่าที่ผมรู้จัก แต่ผมอยากบอกให้ระวังบางอย่างให้มากขึ้น&lt;&#x2F;p&gt;
&lt;p&gt;อย่างแรกคือ การคุมทุกอย่างไว้กับตัวเอง ไม่ได้แปลว่ารับผิดชอบมากกว่าเสมอไป ในหลายกรณี มันคือการสร้างความเสี่ยงโดยไม่รู้ตัว เพราะเมื่อทุกการตัดสินใจต้องผ่านคนคนเดียว ระบบอาจดูนิ่งในวันที่ทุกอย่างปกติ แต่จะเปราะบางทันทีเมื่อคนนั้นไม่พร้อม&lt;&#x2F;p&gt;
&lt;p&gt;อย่างที่สองคือ ทีมที่ดี ไม่ควรขึ้นกับคนคนเดียว ต่อให้คนนั้นจะตั้งใจดี แบกงานเก่ง หรือรู้ระบบมากแค่ไหนก็ตาม ทีมที่เดินต่อได้จริง คือทีมที่สามารถตัดสินใจและรับผิดชอบงานของตัวเองได้ แม้ไม่มีใครคอยยืนอยู่ตรงกลางตลอดเวลา&lt;&#x2F;p&gt;
&lt;p&gt;และสุดท้าย สิ่งที่ผมภูมิใจที่สุดของปีนี้ ไม่ใช่ระบบที่ยังรันอยู่ ไม่ใช่ pipeline ที่เร็วขึ้น หรือ automation ที่ซับซ้อนขึ้น แต่คือการได้เห็นทีมทำงานต่อได้อย่างราบรื่น แม้ในวันที่ผมไม่อยู่ และไม่สามารถช่วยอะไรได้เลย&lt;&#x2F;p&gt;
&lt;p&gt;ถ้ามีอะไรที่อยากบอกตัวเองในวันนั้นจริงๆ ก็คงเป็นว่า การปล่อยบางอย่างออกจากมือ ไม่ได้ทำให้งานแย่ลงเสมอไป บางครั้ง มันคือสิ่งที่จำเป็น เพื่อให้ทั้งทีมและตัวเราเองไปต่อได้ในระยะยาว&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;review-2025-devops-team-reflection-flat-team&#x2F;07-looking-back.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;banthueksan-thuengtawe-ng-aelaephuue-aikhrthiikamlang-yuuaincchudkhlaaykan&quot;&gt;บันทึกสั้นๆ ถึงตัวเอง (และเผื่อใครที่กำลังอยู่ในจุดคล้ายกัน)&lt;a class=&quot;zola-anchor&quot; href=&quot;#banthueksan-thuengtawe-ng-aelaephuue-aikhrthiikamlang-yuuaincchudkhlaaykan&quot; aria-label=&quot;Anchor link for: banthueksan-thuengtawe-ng-aelaephuue-aikhrthiikamlang-yuuaincchudkhlaaykan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ถ้าจะทิ้งอะไรบางอย่างจากปีนี้ไว้ให้ตัวเอง ผมคิดว่ามันไม่ใช่สูตร ไม่ใช่ framework และไม่ใช่ checklist สำหรับการบริหารทีม แต่มันเป็นความเข้าใจบางอย่างที่ผมไม่เคยคิดว่าต้องเรียนรู้จากประสบการณ์ตรงขนาดนี้&lt;&#x2F;p&gt;
&lt;p&gt;ผมเพิ่งเข้าใจว่า ความละเอียดและความตั้งใจดีของเรา อาจกลายเป็น bottleneck ได้โดยไม่รู้ตัว สิ่งที่เคยช่วยให้งานนิ่งในวันที่ทีมยังเล็ก อาจกลายเป็นข้อจำกัดของทีมในวันที่ทุกอย่างเริ่มโตขึ้น&lt;&#x2F;p&gt;
&lt;p&gt;ผมก็เพิ่งเห็นชัดว่า DevOps ที่ทำทุกอย่างเองให้ความเร็วจริง แต่มีต้นทุนที่มองไม่เห็น ทั้งต้นทุนด้านพลังงานของคน และความเสี่ยงจากการผูกการตัดสินใจไว้กับคนเดียว ซึ่งในวันที่ทุกอย่างปกติ มันอาจดูไม่อันตราย แต่จะชัดมากทันทีเมื่อมีอะไรผิดแผน&lt;&#x2F;p&gt;
&lt;p&gt;อีกอย่างหนึ่งที่ผมต้องเตือนตัวเองเสมอคือ การทำทีมให้ flat ไม่ได้แปลว่าปล่อยทุกอย่างออกจากมือ แต่มันคือการเลือกถือเฉพาะสิ่งที่จำเป็น และยอมปล่อย ownership ให้เกิดใกล้กับจุดที่ลงมือทำจริง แม้บางครั้งผลลัพธ์จะไม่ออกมาสมบูรณ์แบบอย่างที่คุ้นเคย&lt;&#x2F;p&gt;
&lt;p&gt;ผมยังได้เรียนรู้ว่า ทีมที่ยั่งยืนไม่ได้เกิดจากการตัดสินใจที่ถูกต้องทุกครั้ง แต่เกิดจากระบบการทำงานที่รองรับความผิดพลาดได้ และทีมที่มีพื้นที่พอจะเรียนรู้จากมันโดยไม่ถูกตัดสินเร็วเกินไป&lt;&#x2F;p&gt;
&lt;p&gt;สุดท้ายแล้ว บทบาทของผมในฐานะผู้นำ อาจไม่ได้อยู่ที่การตัดสินใจให้ถูกที่สุดเสมอไป แต่อยู่ที่การทำให้ทีมกล้าตัดสินใจ และยังไปต่อได้ แม้ผลลัพธ์จะไม่สมบูรณ์แบบในบางครั้ง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;closing-banthueksngthaaypiihnuengkh-ng-devops-team-lead&quot;&gt;Closing: บันทึกส่งท้ายปีหนึ่งของ DevOps Team Lead&lt;a class=&quot;zola-anchor&quot; href=&quot;#closing-banthueksngthaaypiihnuengkh-ng-devops-team-lead&quot; aria-label=&quot;Anchor link for: closing-banthueksngthaaypiihnuengkh-ng-devops-team-lead&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;บทความนี้ไม่ได้ถูกเขียนขึ้นเพื่อบอกว่าวิธีทำงานแบบไหนดีที่สุด หรือทีมทุกทีมควรทำงานแบบ flat เหมือนกันทั้งหมด เพราะบริบทของแต่ละทีมไม่เหมือนกัน และจังหวะของการเปลี่ยนแปลงก็ไม่เท่ากัน&lt;&#x2F;p&gt;
&lt;p&gt;มันเป็นเพียงบันทึกหนึ่งของปีที่ผมได้เรียนรู้ว่า การปล่อยบางอย่างออกจากมือ ไม่ได้แปลว่าเราละเลยความรับผิดชอบ แต่บางครั้ง มันคือความรับผิดชอบในรูปแบบที่ต่างออกไป เป็นความรับผิดชอบต่อทีม ต่อความยั่งยืน และต่อขีดจำกัดของตัวเราเอง&lt;&#x2F;p&gt;
&lt;p&gt;ผมยังไม่แน่ใจว่าสิ่งที่ทำอยู่ตอนนี้คือคำตอบที่ดีที่สุดหรือไม่ แต่สิ่งที่เห็นชัดคือ ทีมสามารถเดินต่อได้ด้วยตัวเองมากขึ้น และตัวผมเองก็มีพื้นที่มากพอที่จะทำหน้าที่ในบทบาทที่ควรจะเป็นจริงๆ&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าบทความนี้จะมีคุณค่าอยู่บ้าง ผมหวังว่ามันอาจช่วยให้ใครบางคนที่กำลังเหนื่อยอยู่กับการแบกทุกอย่างไว้คนเดียว ได้หยุดคิด และถามตัวเองว่า
มีอะไรบ้าง ที่เราไม่จำเป็นต้องถือไว้แน่นเหมือนเดิมแล้วหรือเปล่า&lt;&#x2F;p&gt;
&lt;p&gt;แล้วบางที คำตอบนั้นอาจไม่ต้องรีบหาในวันนี้
เหมือนกับที่ผมเองก็เพิ่งมาเข้าใจมันในปีนี้เช่นกัน&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;แล้วพบกันใหม่ในปีหน้า สวัสดีปีใหม่ครับทุกคน 🎉&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ทำไมแค่ console.log ก็ทำให้ Node.js ช้าลงได้?</title>
		<published>2025-10-05T00:00:00+00:00</published>
		<updated>2025-10-05T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/why-console-log-makes-your-nodejs-slow-and-how-to-fix-it/" type="text/html"/>
		<id>https://thadaw.com/posts/why-console-log-makes-your-nodejs-slow-and-how-to-fix-it/</id>
		<content type="html">&lt;p&gt;สวัสดีเช้าวันอาทิตย์ พอดีวันก่อนได้มีโอกาสไปเห็นโพสต์ Twitter นึง โพสต์ถึงเรื่องของการที่ลบคอนโซลล็อก (&lt;code&gt;console.log&lt;&#x2F;code&gt;) ออกไปจาก Node.js แล้วก็ทำให้ &lt;strong&gt;Performance ของ Server ดีขึ้น เยอะเลย&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;why-console-log-makes-your-nodejs-slow-and-how-to-fix-it&#x2F;server-log.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ref: Node.js event loop utilization for one our services went from about 80% to 20% just by removing logs by @maverickdotdev 🤦&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;maverickdotdev&#x2F;status&#x2F;1971249969463165313&quot;&gt;https:&#x2F;&#x2F;x.com&#x2F;maverickdotdev&#x2F;status&#x2F;1971249969463165313&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ทีนี้พอเราเห็นเรื่องนี้ ผมคิดว่าหลาย ๆ คนน่าจะต้องสงสัยแน่เลย ไม่ว่าจะเป็นมือใหม่ในการเขียน Node.js เอง หรือคนที่เขียนมาสักระยะนึงแล้ว จริง ๆ แล้วเราอาจจะต้องเข้าใจก่อนว่า &lt;strong&gt;ตัว &lt;code&gt;console.log&lt;&#x2F;code&gt; ซึ่งเป็นคำสั่งในกลุ่ม &lt;code&gt;console&lt;&#x2F;code&gt; ของ Node.js เอง&lt;&#x2F;strong&gt; เราต้องทำความเข้าใจก่อนว่า &lt;strong&gt;Node.js เนี่ย มันทำงานเป็น Event Loop&lt;&#x2F;strong&gt; ใช่ไหมครับ เดี๋ยวผมจะมีบล็อกอธิบายเรื่อง Event Loop อีกทีนึง แต่โดยสรุปคือ Event Loop ของ Node.js เนี่ย มันจะพูดถึงการทำงานแบบ &lt;strong&gt;Single Thread&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;why-console-log-makes-your-nodejs-slow-and-how-to-fix-it&#x2F;block-event-loop.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;คำว่า Single Thread ก็คือว่า อะไรก็ตามที่มันทำงาน มันจัดการงานหลายอย่างแบบ concurrent ผ่าน Event Loop แม้จะมีเพียง main thread เดียว ประโยชน์แน่นอนครับว่า Single Thread เนี่ย มันช่วยทำให้เราสามารถที่จะใช้ทรัพยากร CPU ได้อย่างมีประสิทธิภาพ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;console-log&quot;&gt;console.log&lt;a class=&quot;zola-anchor&quot; href=&quot;#console-log&quot; aria-label=&quot;Anchor link for: console-log&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ทีนี้มากลับมาที่เรื่องของ &lt;code&gt;console.log&lt;&#x2F;code&gt; กันบ้าง &lt;strong&gt;ตัวคำสั่งที่เป็น &lt;code&gt;console.log&lt;&#x2F;code&gt; หรือประเภท &lt;code&gt;console&lt;&#x2F;code&gt; อื่น ๆ พวกนี้มันเป็นคำสั่งประเภท synchronous&lt;&#x2F;strong&gt; หลาย ๆ คนก็อาจจะสงสัยว่า จริง ๆ แล้ว Node.js ทำงานแบบ asynchronous เป็นหลักอยู่แล้ว (สำหรับ I&#x2F;O, network, timers) แต่ทำไมการทำงานแบบ synchronous ถึงมีปัญหา&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;p&gt;อ่านต่อที่ Official Documentation ของ Node.js เรื่อง Console: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nodejs.org&#x2F;api&#x2F;process.html#a-note-on-process-io&quot;&gt;https:&#x2F;&#x2F;nodejs.org&#x2F;api&#x2F;process.html#a-note-on-process-io&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;งั้นเดี๋ยวมาอธิบายกัน คือการทำงานแบบ synchronous เนี่ย มันไปบล็อก Main Thread ซึ่ง Node.js เนี่ย มันมี Main Thread อยู่อันเดียว หมายความว่ามันจะไปบล็อกการทำงานของ Event Loop (โค้ด JavaScript ภายใน callback&#x2F;function ยังคงรันแบบ synchronous ได้ และคำสั่ง &lt;code&gt;console.log&lt;&#x2F;code&gt; อาจบล็อก Event Loop ขึ้นอยู่กับว่า &lt;code&gt;stdout&lt;&#x2F;code&gt; เชื่อมต่อไปที่ terminal, file หรือ pipe) &lt;strong&gt;ถ้าเราเอา &lt;code&gt;console.log&lt;&#x2F;code&gt; ใส่เยอะ ๆ มันก็จะส่งผล Performance ตามมา เพราะว่า Event Loop ก็จะถูกบล็อกไปด้วย&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thaang-k&quot;&gt;ทางออก&lt;a class=&quot;zola-anchor&quot; href=&quot;#thaang-k&quot; aria-label=&quot;Anchor link for: thaang-k&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลาย ๆ คนก็อาจจะมีคำถามตามมาว่า ถ้าเราไม่ได้ใช้ &lt;code&gt;console.log&lt;&#x2F;code&gt; แล้วเราจะสามารถพ่น Log ออกมาทาง Terminal หรือทาง STDOUT ได้ยังไง การที่เราพ่น Log มาเนี่ย มันทำได้หลายวิธี วิธีการที่ไม่ไปบล็อก Thread เนี่ย มันก็จะมี Library ที่เข้ามาแก้ปัญหา ยกตัวอย่างเช่น เหมือนที่ผมใช้อยู่ก็จะเป็น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pinojs&#x2F;pino&quot;&gt;&lt;strong&gt;Pino&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt; ผมใช้บ่อยกว่า Pino ตัวที่เค้าเอามาแก้ปัญหาเรื่อง Log&lt;&#x2F;p&gt;
&lt;p&gt;จริง ๆ หลายคนอาจจะบอกว่า ฉันก็เขียน Log เองก็ได้นี่ ฉันเขียน Interface มาก็ได้นี่ ทำไมฉันจะต้องใช้ Pino เพราะว่าฉันก็สามารถที่จะเขียนตัวกลไกของ Log เองได้ ใช้ Level ได้ Log ที่ถูกออกแบบมาเพื่อแก้ปัญหาหนึ่งคือ&lt;&#x2F;p&gt;
&lt;p&gt;เรื่องของการบล็อก Thread ของ &lt;code&gt;console.log&lt;&#x2F;code&gt; นี่แหละ แทนที่เราจะพ่น Log ออกไปทางใดก็ตามแล้วมันจะไปบล็อก Thread ใช่ไหม &lt;strong&gt;การที่เราใช้ Pino เนี่ย เค้าจะใช้วิธีการ คือเขามีการ &quot;แตก Worker Thread&quot; ออกมา&lt;&#x2F;strong&gt; คือมีการใช้ &lt;strong&gt;อีกเทรดนึงเพื่อที่จะมาจัดการเรื่องของการทำ Logging โดยเฉพาะเลย&lt;&#x2F;strong&gt; ทำให้เวลาที่เราสั่งคำสั่ง Log ผ่าน Pino มันก็จะทำได้อย่างรวดเร็วมาก &lt;strong&gt;เพราะว่ามันไม่ไปบล็อก Main Thread นั่นเอง&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;พอมันออกไปทาง Pino แล้ว เราจะไปตั้งค่า transport ได้ ซึ่งเจ้า transport ก็คือ การตั้งค่าขาออกของ Log ว่าจะให้ไปออกที่ไหนก็แล้วแต่ อย่างเช่น อาจจะเป็น console อาจจะเป็นไฟล์ อาจจะเป็นที่ไหนก็ได้ ที่เราจะตั้งค่าให้มันออกไป ถึงแม้ว่าเราจะใช้ &lt;code&gt;console.log&lt;&#x2F;code&gt; บน Pino แล้วก็ตาม มันก็ยังไม่ช้า เพราะว่า Pino จัดการเรื่องของการจัดการเทรดที่เป็น Worker Thread แล้ว&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thamaimkaar-bundle-kab-pino-thuengyaakkhuen&quot;&gt;ทำไมการ Bundle กับ Pino ถึงยากขึ้น?&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaimkaar-bundle-kab-pino-thuengyaakkhuen&quot; aria-label=&quot;Anchor link for: thamaimkaar-bundle-kab-pino-thuengyaakkhuen&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;ใครที่ไม่ได้สนใจเรื่องของการ Bundle Node.js สามารถข้ามส่วนนี้ไปได้เลยครับ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;แต่เดี๋ยวก่อน ใครที่ใช้ Pino จะมีการเจอ Challenge ของการทำ bundling ที่จะทำให้ Node Application เวลาที่เรามีการ bundle มัน หรือเวลาที่เราต้องการจะลดขนาด หรือทำ Docker Image ขนาดเล็ก มันก็จะทำได้ยุ่งยากขึ้น ผมเคยเขียนบทความเกี่ยวข้องกับโจทย์ เวลาที่เราต้อง bundle Node.js ที่มีการใช้งานท่าประหลาด ๆ ใน Node.js ซึ่งหนึ่งในท่าประหลาด ๆ คือเรื่องของ Pino &lt;strong&gt;เพราะว่า Pino เวลาที่มันจัดการ Worker Thread มันจะมีการสร้างไฟล์ขึ้นมาใหม่&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;p&gt;บทความที่เกี่ยวข้อง: &lt;a href=&quot;&#x2F;posts&#x2F;why-nodejs-bundle-hard&quot;&gt;ทำไมการ Bundle Node.js ที่ใช้ Worker Threads ถึงยาก?&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ถ้าเราไม่ได้มีการจัดการอย่างดี ไฟล์พวกนี้ที่มันถูกสร้างมาใหม่ เวลาที่มัน bundle เวลาที่โปรแกรมที่เป็นอย่างเช่น ES Build bundle มันจะไม่เห็นไฟล์พวกนี้ &lt;strong&gt;มันก็เลยทำให้เกิด Runtime Error ได้&lt;&#x2F;strong&gt; ก็เป็นสิ่งที่เราควรระมัดระวัง&lt;&#x2F;p&gt;
&lt;p&gt;หวังว่าบทความนี้จะเป็นประโยชน์กับทุก ๆ คน&lt;&#x2F;p&gt;
&lt;p&gt;สำหรับวันนี้ไปก่อนครับ สวัสดีครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ทำไมการ Bundle Node.js ให้ไฟล์เล็กลง ถึงไม่ง่ายอย่างที่คิด</title>
		<published>2025-09-27T00:00:00+00:00</published>
		<updated>2025-09-27T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/why-nodejs-bundle-hard/" type="text/html"/>
		<id>https://thadaw.com/posts/why-nodejs-bundle-hard/</id>
		<content type="html">&lt;p&gt;สวัสดีครับ วันนี้มาเขียนบล็อกนะครับ เป็นสิ่งที่เก็บรวบรวมข้อมูลแล้วก็ประสบการณ์อยู่นาน ก็คือว่าด้วยเรื่องของว่าทำไมถึงเวลาที่เราใช้ Node.js โปรเจกต์ถึงมีขนาดใหญ่ และทำไมการ bundle ถึงไม่ง่ายอย่างที่คิดนะครับ แต่บอกก่อนว่าจริง ๆ แล้วเราอาจจะใช้ bundle ได้ แต่มันจะมีบางกรณีที่อาจจะใช้ไม่ได้นะครับ โอเค เป็นยังไงไปดูกันครับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;why-nodejs-bundle-hard&#x2F;too-many-deps.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;หากเรามาจากฝั่งเว็บ เราอาจจะคุ้นเคยกับคำว่า &quot;Bundler&quot; เป็นอย่างดี ไม่ว่าจะเป็นเครื่องมืออย่าง Webpack, Rollup, หรือ Vite ที่ทำหน้าที่รวมไฟล์ JavaScript, CSS, และ assets ต่างๆ ให้เหลือเพียงไม่กี่ไฟล์เพื่อประสิทธิภาพในการโหลดบนเบราว์เซอร์ ในโลกของการพัฒนาเว็บ การทำ bundle ถือเป็นเรื่องปกติและเครื่องมือเหล่านี้ก็ถูกพัฒนามาอย่างดีมากๆ จนหลายครั้งเราแทบไม่ต้องเข้าไปยุ่งกับการตั้งค่าที่ซับซ้อนเลย&lt;&#x2F;p&gt;
&lt;p&gt;แนวคิดเดียวกันนี้จึงถูกนำมาปรับใช้กับฝั่ง Node.js เพื่อแก้ปัญหา &lt;code&gt;node_modules&lt;&#x2F;code&gt; ที่มีขนาดใหญ่ โดยเฉพาะเมื่อเราต้องจัดการกับ Docker image ที่อาจบวมไปถึงระดับ GB ได้ การใช้ Bundler จะช่วยวิเคราะห์โค้ดของเรา แล้วดึงเฉพาะส่วนที่จำเป็นจริงๆ มารวมกันเป็นไฟล์เล็กๆ ทำให้เราไม่ต้อง copy &lt;code&gt;node_modules&lt;&#x2F;code&gt; ทั้งหมดเข้าไปใน image แต่เส้นทางกลับไม่ได้โรยด้วยกลีบกุหลาบเหมือนฝั่งเว็บ และนี่คือเหตุผลที่มันอาจจะไม่ใช่ Silver Bullet สำหรับทุกกรณีครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;krniithii-bundler-miipayhaa-dynamic-imports-aela-decorators&quot;&gt;กรณีที่ Bundler มีปัญหา: Dynamic Imports และ Decorators&lt;a class=&quot;zola-anchor&quot; href=&quot;#krniithii-bundler-miipayhaa-dynamic-imports-aela-decorators&quot; aria-label=&quot;Anchor link for: krniithii-bundler-miipayhaa-dynamic-imports-aela-decorators&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;อย่างเช่นตัวที่มีปัญหาเยอะ ๆ ก็จะเป็นพวกเวลาที่เราใช้ bundler อย่าง esbuild&lt;&#x2F;strong&gt; เนื่องจาก bundler ประเภทนี้ทำงานแบบ Static Analysis คือมันจะวิเคราะห์โค้ด ณ เวลาที่ build โดยไม่ได้รันโค้ดจริง ดังนั้น ถ้าเรามีการเรียกใช้โมดูลแบบ dynamic หรือใช้เทคนิคบางอย่างที่ไม่ได้แสดงความเชื่อมโยงของไฟล์อย่างชัดเจน bundler ก็จะไม่สามารถตามไปเก็บโค้ดส่วนนั้นมารวมได้&lt;&#x2F;p&gt;
&lt;p&gt;ตัวอย่างที่เห็นได้ชัดคือ &lt;strong&gt;NestJS&lt;&#x2F;strong&gt; ซึ่งเป็นเฟรมเวิร์กที่ใช้ &lt;strong&gt;Dependency Injection (DI)&lt;&#x2F;strong&gt; และ &lt;strong&gt;Decorators&lt;&#x2F;strong&gt; เยอะมาก ถ้าเราลองเอา esbuild ไป build โปรเจกต์ NestJS ตรงๆ สิ่งที่เกิดขึ้นก็คือพวก Service ต่างๆ ที่ถูกเรียกผ่าน decorator อาจจะไม่ถูก bundle เข้ามาด้วย เพราะในมุมมองของ static bundler มันไม่เห็นว่ามีการ &lt;code&gt;import&lt;&#x2F;code&gt; ไฟล์เหล่านั้นโดยตรง&lt;&#x2F;p&gt;
&lt;p&gt;เพื่อแก้ปัญหานี้ เราจำเป็นต้องใช้ plugin เข้ามาช่วยครับ มีผู้พัฒนาที่เจอ workaround สำหรับปัญหานี้และได้สร้าง plugin ที่ชื่อว่า &lt;strong&gt;&lt;code&gt;@anatine&#x2F;esbuild-decorators&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; ขึ้นมาเพื่อจัดการตรงนี้โดยเฉพาะ โดยเราสามารถเพิ่ม plugin นี้เข้าไปใน config ของ esbuild เพื่อให้มันสามารถ bundle โค้ดที่ใช้ decorator ของ NestJS ได้อย่างถูกต้อง&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ตัวอย่าง custom esbuild config&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;BuildOptions&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;esbuild&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;esbuildDecorators&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;@anatine&#x2F;esbuild-decorators&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;tsconfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;path&#x2F;to&#x2F;your&#x2F;tsconfig.json&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-variable z-object z-process z-ts&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-process z-ts&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;buildConfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;BuildOptions&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;entryPoints&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;src&#x2F;main.ts&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;bundle&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-true z-ts&quot;&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;platform&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;node&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;outdir&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;dist&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;tsconfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;plugins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;esbuildDecorators&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; เพิ่ม plugin เข้าไปตรงนี้&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;tsconfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ... config ส่วนอื่นๆ&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;buildConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;p&gt;ผมเคยเขียนบทความเต็มๆ เกี่ยวกับการใช้ esbuild ใช้คู่กับ plugin &lt;strong&gt;@anatine&#x2F;esbuild-decorators&lt;&#x2F;strong&gt; กับ NestJS ไว้ด้วยนะครับ เผื่อใครสนใจลองอ่านดูได้ที่ &lt;a href=&quot;&#x2F;posts&#x2F;reduce-nestjs-docker-image-size-with-esbuild-bundle&quot;&gt;บทความนี้&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;&lt;h3 id=&quot;iikhnuengtaw-yaangsudkhlaassik-kaarcchadkaar-log-dwy-pino&quot;&gt;อีกหนึ่งตัวอย่างสุดคลาสสิก: การจัดการ Log ด้วย Pino&lt;a class=&quot;zola-anchor&quot; href=&quot;#iikhnuengtaw-yaangsudkhlaassik-kaarcchadkaar-log-dwy-pino&quot; aria-label=&quot;Anchor link for: iikhnuengtaw-yaangsudkhlaassik-kaarcchadkaar-log-dwy-pino&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;อีกกรณีหนึ่งก็คือการเขียน log ครับ ปกติเราอาจจะใช้ &lt;code&gt;console.log&lt;&#x2F;code&gt; ซึ่งเป็นวิธีที่ง่าย แต่ข้อเสียคือมันเป็นการทำงานแบบ &lt;strong&gt;Block I&#x2F;O&lt;&#x2F;strong&gt; หมายความว่าถ้าเราเขียน log บ่อยๆ มันก็จะทำให้ Performance ของแอปเราช้าลงได้ หลายคนจึงหันไปใช้ Logger ตัวอื่นอย่าง &lt;strong&gt;Pino&lt;&#x2F;strong&gt; ที่ออกแบบมาให้ทำงานแบบ Asynchronous โดยการแตก thread ไปใช้ &lt;strong&gt;worker thread&lt;&#x2F;strong&gt; ของ Node.js เพื่อไม่ให้การเขียน log มาขัดขวางการทำงานของ main thread ครับ&lt;&#x2F;p&gt;
&lt;p&gt;แต่พอมีการใช้ worker thread นี่แหละครับที่ทำให้การ bundle ซับซ้อนขึ้น เพราะโดยพื้นฐานแล้ว Pino &lt;strong&gt;ไม่สามารถถูกรวมเป็นไฟล์เดียว (single-file bundle) ได้&lt;&#x2F;strong&gt; เนื่องจากสถาปัตยกรรมของมันต้องแยกไฟล์ worker ออกมาต่างหาก&lt;&#x2F;p&gt;
&lt;p&gt;โชคดีที่ถ้าเราใช้ bundler ยอดนิยมอย่าง esbuild เขาก็มี plugin อย่าง &lt;code&gt;esbuild-plugin-pino&lt;&#x2F;code&gt; มาให้เลย ซึ่งมันจะช่วยจัดการสร้างไฟล์ worker ที่จำเป็น (เช่น &lt;code&gt;thread-stream.js&lt;&#x2F;code&gt;) แยกออกมาให้โดยอัตโนมัติ ทำให้เราแค่ติดตั้งและตั้งค่านิดหน่อยก็สามารถใช้งานได้เลย&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ตัวอย่างการใช้ plugin ของ pino&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;build&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;esbuild&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;esbuildPluginPino&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;esbuild-plugin-pino&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;entryPoints&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;src&#x2F;index.ts&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;outdir&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dist&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;platform&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;node&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;bundle&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-true z-ts&quot;&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;plugins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;esbuildPluginPino&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;transports&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;pino-pretty&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;p&gt;สามารถอ่านรายละเอียดเพิ่มเติมเกี่ยวกับการใช้ Pino กับการ Bundle ได้ที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pinojs&#x2F;pino&#x2F;blob&#x2F;main&#x2F;docs&#x2F;bundling.md&quot;&gt;pino documentation&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;&lt;h3 id=&quot;aelwthaaaimmii-plugin-aihaichla&quot;&gt;แล้วถ้าไม่มี Plugin ให้ใช้ล่ะ?&lt;a class=&quot;zola-anchor&quot; href=&quot;#aelwthaaaimmii-plugin-aihaichla&quot; aria-label=&quot;Anchor link for: aelwthaaaimmii-plugin-aihaichla&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ทีนี้เราก็ได้เห็นแล้วนะครับว่าถ้ามี plugin ชีวิตก็จะสบายขึ้นมาก แต่ถ้าไม่มีล่ะ? เราจะทำยังไง? ทางเลือกหลักๆ ก็จะมีอยู่ประมาณนี้ครับ:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ทำด้วยมือ (Manual Scripting):&lt;&#x2F;strong&gt; วิธีนี้คือการเขียนสคริปต์ของเราเองเพื่อคัดลอกไฟล์ที่จำเป็นของ Pino ไปวางไว้ในโฟลเดอร์ &lt;code&gt;dist&lt;&#x2F;code&gt; หลังจากการ build เสร็จสิ้น เหตุผลที่ต้องทำแบบนี้เพราะสถาปัตยกรรมของ Pino ที่ใช้ Worker Threads ทำให้มันไม่สามารถถูก &quot;บันเดิลเป็นไฟล์เดียวล้วนๆ&quot; ได้อยู่แล้ว ซึ่งพวก plugin มันก็แค่มาช่วยทำให้กระบวนการนี้เป็นอัตโนมัติให้เรานั่นเอง&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ใช้กลยุทธ์ &quot;External Deps&quot;:&lt;&#x2F;strong&gt; เราสามารถบอก bundler ได้ว่า &quot;ไม่ต้องพยายาม bundle library พวก &lt;code&gt;pino&lt;&#x2F;code&gt; หรือ &lt;code&gt;thread-stream&lt;&#x2F;code&gt; นะ&quot; โดยกำหนดให้มันเป็น external dependencies วิธีนี้จะทำให้โค้ดของเรา build ผ่าน และแก้ปัญหาเรื่องการหาไฟล์ worker ได้ แต่ก็มีข้อแลกเปลี่ยนที่สำคัญคือ &lt;strong&gt;ขนาด image ของเราจะไม่เล็กลงตามเป้าหมาย&lt;&#x2F;strong&gt; เพราะสุดท้ายเราก็ยังต้อง copy &lt;code&gt;node_modules&lt;&#x2F;code&gt; ที่มี dependencies เหล่านี้ติดไปด้วยอยู่ดี&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;หลีกเลี่ยงการใช้ Worker ไปเลย:&lt;&#x2F;strong&gt; อีกทางเลือกคือการปรับการตั้งค่าของ Pino ให้ไปใช้ transport ที่ไม่ได้ทำงานบน worker thread (เช่น เขียน log ไปที่ stdout หรือเขียนไฟล์ใน main thread โดยตรง) วิธีนี้จะช่วยลดความซับซ้อนในการ build ลงได้มาก แต่เราก็จะเสียข้อดีเรื่องการแยกงาน I&#x2F;O หนักๆ ออกจาก event loop ซึ่งเป็นแนวทางที่ Pino แนะนำสำหรับงานบน production&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;สรุปก็คือ&lt;&#x2F;strong&gt; ถ้ามี plugin ก็ใช้เถอะครับ สบายสุดแล้ว เพราะมันจัดการเรื่องยากๆ ให้เราอัตโนมัติ แต่ถ้าไม่มีจริงๆ การทำด้วยมือหรือการใช้ external ก็ยังเป็นทางออกที่พอไปได้ แค่เราต้องยอมรับ trade-off ที่ตามมา ไม่ว่าจะเป็นเรื่องขนาดของ image หรือประสิทธิภาพที่อาจลดลง ซึ่งก็ต้องเลือกให้เหมาะกับบริบทของโปรเจกต์เราครับ&lt;&#x2F;p&gt;
&lt;p&gt;ก็หวังว่าจะเป็นประโยชน์กันนะครับ สวัสดีครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>เข้าใจพื้นฐานของ DNS และการย้าย DNS ไปยัง Azure DNS Zone</title>
		<published>2025-09-09T00:00:00+00:00</published>
		<updated>2025-09-09T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/understanding-dns-and-move-to-azure-dns/" type="text/html"/>
		<id>https://thadaw.com/posts/understanding-dns-and-move-to-azure-dns/</id>
		<content type="html">&lt;p&gt;สวัสดีครับ วันนี้อยากมาเล่าเรื่อง &lt;strong&gt;DNS Zone และการย้ายโดเมนมาที่ Azure DNS Zone&lt;&#x2F;strong&gt; กันแบบง่าย ๆ หลายคนอาจเคยได้ยินคำว่า DNS แล้วรู้สึกว่าเป็นศัพท์เทคนิคที่ซับซ้อน แต่จริง ๆ แล้ว DNS ก็คือ &lt;strong&gt;สมุดโทรศัพท์ของอินเทอร์เน็ต&lt;&#x2F;strong&gt; นี่เองครับ ถ้าเปรียบเทียบให้เห็นภาพ: โดเมนเนม (&lt;code&gt;example.com&lt;&#x2F;code&gt;) ก็เหมือน “ชื่อคน” ในสมุดโทรศัพท์, IP Address (&lt;code&gt;1.2.3.4&lt;&#x2F;code&gt;) ก็เหมือน “เบอร์โทรศัพท์จริง” ส่วน DNS Record คือบันทึกที่บอกว่า &lt;em&gt;ชื่อนี้ต้องโทรไปที่เบอร์ไหน&lt;&#x2F;em&gt; เวลาที่เบราว์เซอร์อยากเข้าเว็บ มันก็แค่เปิดสมุดโทรศัพท์เล่มนี้ดู แล้วรู้ทันทีว่าจะต้องวิ่งไปที่ IP ไหนถึงจะเจอเว็บไซต์ของเรา&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;understanding-dns-and-move-to-azure-dns&#x2F;dns-internet-phonebook.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;phuuenthaankh-ng-dns&quot;&gt;พื้นฐานของ DNS&lt;a class=&quot;zola-anchor&quot; href=&quot;#phuuenthaankh-ng-dns&quot; aria-label=&quot;Anchor link for: phuuenthaankh-ng-dns&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;แล้วในสมุดโทรศัพท์ของอินเทอร์เน็ตเอง ก็ไม่ได้มีแค่ &lt;strong&gt;“ชื่อ → เบอร์”&lt;&#x2F;strong&gt; แบบเดียว แต่ยังมีหลายประเภทของการเชื่อมต่อ ที่บอกว่าโดเมนควรวิ่งไปหาปลายทางแบบไหนบ้าง ตัวอย่างที่เจอบ่อย ๆ ได้แก่&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A Record&lt;&#x2F;strong&gt; → ระบุว่า &lt;em&gt;ชื่อนี้&lt;&#x2F;em&gt; ต้องชี้ไปยัง &lt;em&gt;หมายเลขบ้านจริง&lt;&#x2F;em&gt; (IP Address แบบตัวเลข)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CNAME Record&lt;&#x2F;strong&gt; → เป็นเหมือน &lt;em&gt;ชื่อเล่น&lt;&#x2F;em&gt; ของชื่อหลัก เช่น &lt;code&gt;www.example.com&lt;&#x2F;code&gt; ชี้ไปที่ &lt;code&gt;example.com&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;MX Record&lt;&#x2F;strong&gt; → ใช้สำหรับ &lt;em&gt;อีเมล&lt;&#x2F;em&gt; บอกว่าถ้ามีใครจะส่งจดหมาย (อีเมล) มาที่ &lt;code&gt;@example.com&lt;&#x2F;code&gt; ต้องไปที่ “ไปรษณีย์เซิร์ฟเวอร์” ไหน&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;TXT Record&lt;&#x2F;strong&gt; → เป็นเหมือน &lt;em&gt;โน้ตสั้น ๆ&lt;&#x2F;em&gt; ที่แนบไว้กับชื่อ เช่น การยืนยันความเป็นเจ้าของโดเมน หรือการตั้งค่าความปลอดภัยของอีเมล&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;แต่ถ้าวันหนึ่งเราไม่ได้อยากใช้แค่เว็บสำเร็จรูปของผู้ให้บริการแล้ว เช่น อยากเอาโดเมนนี้ไปชี้เข้ากับแอปที่รันอยู่บน Azure, ใช้กับอีเมลของ Microsoft 365 หรือ Google Workspace, หรืออยากควบคุม DNS ด้วยโค้ด (Infrastructure as Code) ปัญหาจะเริ่มตามมาทันทีครับ เพราะ DNS Record ที่ผู้ให้บริการตั้งมาให้อาจไม่ตรงกับสิ่งที่เราต้องการ หรือบางครั้ง panel ของผู้ให้บริการก็ไม่ยืดหยุ่นพอที่จะรองรับการตั้งค่าซับซ้อน เมื่อถึงจุดนี้เองที่เราจะเริ่มเห็นประโยชน์ของการ “ย้าย DNS Zone” มาจัดการเองบน Azure DNS ครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thamaimthuengt-ngaich-azure-dns&quot;&gt;ทำไมถึงต้องใช้ Azure DNS&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaimthuengt-ngaich-azure-dns&quot; aria-label=&quot;Anchor link for: thamaimthuengt-ngaich-azure-dns&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;สาเหตุที่หลายคนเลือกจะย้าย DNS มาจัดการเองบน Azure DNS ก็เพราะว่ามันช่วยให้เราควบคุมได้มากกว่าการปล่อยให้ผู้ให้บริการโดเมนเป็นคนจัดการครับ อย่างแรกเลยคือเรื่อง &lt;strong&gt;ความยืดหยุ่น&lt;&#x2F;strong&gt; เวลาเราอยากเพิ่ม record แปลก ๆ หรือแก้ไขค่าให้ตรงกับระบบที่เราสร้างเอง บางที panel ของผู้ให้บริการเดิมไม่รองรับ แต่บน Azure DNS เราตั้งค่าได้เต็มที่ อีกอย่างคือมันรองรับการทำงานแบบ &lt;strong&gt;Automation&lt;&#x2F;strong&gt; ผ่าน API, Azure CLI หรือ Terraform ซึ่งสำคัญมากเวลาที่เรามีหลาย environment เช่น Dev, UAT, Prod แล้วอยากให้ DNS ถูกสร้างและอัปเดตแบบอัตโนมัติพร้อมกับระบบอื่น ๆ สุดท้ายคือ &lt;strong&gt;การเชื่อมต่อกับบริการ Azure อื่น ๆ&lt;&#x2F;strong&gt; ที่ทำได้เนียนกว่า เช่น App Service, Container App หรือ VM พอใช้ DNS ของ Azure อยู่แล้ว การผูก custom domain เข้ากับ service เหล่านี้ก็สะดวกขึ้นมากครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;dns-thamngaanyangaing&quot;&gt;DNS ทำงานยังไง&lt;a class=&quot;zola-anchor&quot; href=&quot;#dns-thamngaanyangaing&quot; aria-label=&quot;Anchor link for: dns-thamngaanyangaing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลายคนอาจจะสงสัยว่า เวลาที่เราซื้อโดเมนมาแล้ว เราจะเอาโดเมนนี้ไปใช้กับบริการ DNS ของเจ้าอื่นได้ยังไง เพราะอาจเข้าใจว่าการซื้อโดเมนมันเหมือนกับการสมัครใช้ซอฟต์แวร์แบบ Subscription (SaaS) ที่ล็อกเราไว้กับระบบของเขา ย้ายออกไปที่อื่นแทบจะเป็นไปไม่ได้ แต่ความจริงแล้วการ “ซื้อโดเมน” คือการจดทะเบียนชื่อบนอินเทอร์เน็ตครับ ส่วนบริการ DNS ที่แถมมาด้วยเป็นแค่ ตัวช่วย ที่ registrar เตรียมไว้ให้เราเท่านั้น เราสามารถเลือกได้เลยว่าจะใช้ DNS ของเขา หรือย้ายไปใช้ DNS Provider รายอื่น เช่น Azure DNS หรือ Cloudflare โดยทำได้แค่การเปลี่ยน Nameserver ของโดเมนให้ชี้ไปยังระบบใหม่เท่านั้นเอง&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;understanding-dns-and-move-to-azure-dns&#x2F;how-dns-work.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;เพื่อให้เห็นภาพชัดขึ้น ลองมาดูกันครับว่าเวลาเรามี &lt;strong&gt;Domain, DNS และ Nameserver&lt;&#x2F;strong&gt; ทั้งสามอย่างนี้ทำงานร่วมกันยังไง&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Domain&lt;&#x2F;strong&gt; → คือ “ชื่อ” ที่เราจดทะเบียนไว้ เช่น &lt;code&gt;example.com&lt;&#x2F;code&gt; คล้าย ๆ กับการที่เราไปจองชื่อร้านในห้าง ว่าชื่อนี้เป็นของเราแล้ว คนอื่นจะมาใช้ชื่อเดียวกันไม่ได้&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;DNS Record&lt;&#x2F;strong&gt; → คือ “กฎการแปลงชื่อ” ว่าเวลามีคนเรียก &lt;code&gt;example.com&lt;&#x2F;code&gt; ต้องไปที่ไหนต่อ เช่น A record ชี้ไป IP ของเซิร์ฟเวอร์, MX record ชี้ไปเซิร์ฟเวอร์อีเมล&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Nameserver (NS)&lt;&#x2F;strong&gt; → คือ “คนเฝ้าสมุดโทรศัพท์” คอยตอบคำถามเวลามีคนมาถามว่าชื่อนี้ต้องไปที่ไหน สมมติเราเปลี่ยน nameserver ของโดเมนไปเป็นของ Azure DNS ก็หมายความว่า ต่อจากนี้ใครก็ตามที่ถามข้อมูลเกี่ยวกับ &lt;code&gt;example.com&lt;&#x2F;code&gt; จะต้องไปถาม Azure DNS เพื่อให้มันตอบกลับมา&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ดังนั้นภาพรวมการทำงานคือ &lt;strong&gt;Domain&lt;&#x2F;strong&gt; เป็นชื่อ, &lt;strong&gt;DNS Record&lt;&#x2F;strong&gt; คือกฎการชี้ทาง, และ &lt;strong&gt;Nameserver&lt;&#x2F;strong&gt; คือผู้ให้บริการที่ถือสมุดบันทึกนี้ไว้ พอเราย้าย nameserver ไปเจ้าไหน ก็เท่ากับว่ามอบสิทธิ์การจัดการ DNS Record ทั้งหมดให้เจ้านั้นไปดูแลครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ewlaathiieraaekhaa-example-com-manthamngaanyangaing&quot;&gt;เวลาที่เราเข้า example.com มันทำงานยังไง?&lt;a class=&quot;zola-anchor&quot; href=&quot;#ewlaathiieraaekhaa-example-com-manthamngaanyangaing&quot; aria-label=&quot;Anchor link for: ewlaathiieraaekhaa-example-com-manthamngaanyangaing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ลองมาดูขั้นตอนการทำงานของ DNS กันแบบละเอียด ๆ ครับ สมมติว่าเรามีโดเมน &lt;code&gt;example.com&lt;&#x2F;code&gt; ที่จดทะเบียนกับ Google Domain แล้วตั้ง nameserver ไปที่ Azure DNS Zone ที่เราสร้างไว้ (เช่น &lt;code&gt;ns1-01.azure-dns.com&lt;&#x2F;code&gt;, &lt;code&gt;ns2-01.azure-dns.net&lt;&#x2F;code&gt;, etc.) และใน Azure DNS Zone เราตั้ง A record ให้ &lt;code&gt;example.com&lt;&#x2F;code&gt; ชี้ไปที่ IP ของเว็บเซิร์ฟเวอร์ที่รันอยู่บน Azure (เช่น &lt;code&gt;20.50.100.25&lt;&#x2F;code&gt;) เวลาที่ผู้ใช้พิมพ์ &lt;code&gt;example.com&lt;&#x2F;code&gt; ในเบราว์เซอร์ ขั้นตอนการทำงานจะเป็นดังนี้ครับ:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ผู้ใช้พิมพ์ &lt;code&gt;example.com&lt;&#x2F;code&gt; ใน browser&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Browser จะถามระบบปฏิบัติการก่อนว่าเคยเก็บ IP ของ &lt;code&gt;example.com&lt;&#x2F;code&gt; ไว้ใน cache ไหม (เหมือนเราเคยจดเบอร์โทรเพื่อนลงมือถือไว้แล้ว)&lt;&#x2F;li&gt;
&lt;li&gt;ถ้าไม่มี → ต้องไปถามคนอื่น (DNS Resolver)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DNS Resolver รับหน้าที่ตามหาคำตอบ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Resolver เปรียบเหมือน “คนกลาง” ที่เราส่งคำถามไปให้ เช่น DNS ของ ISP, Google (8.8.8.8), หรือ Cloudflare (1.1.1.1)&lt;&#x2F;li&gt;
&lt;li&gt;ถ้า resolver ไม่เคยเจอ &lt;code&gt;example.com&lt;&#x2F;code&gt; มาก่อน → มันต้องเริ่มออกเดินทางตามหา&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ถาม Root Server ก่อน&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Root Server คือ “สารบัญใหญ่สุด” ของโลกอินเทอร์เน็ต&lt;&#x2F;li&gt;
&lt;li&gt;มันจะไม่รู้ว่า &lt;code&gt;example.com&lt;&#x2F;code&gt; อยู่ที่ไหน แต่จะตอบว่า
👉 &lt;em&gt;“อ๋อ ชื่อที่ลงท้ายด้วย .com ต้องไปถามที่ &lt;strong&gt;.com TLD Server&lt;&#x2F;strong&gt; นะ”&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ไปถาม TLD Server (.com)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;TLD Server ของ &lt;code&gt;.com&lt;&#x2F;code&gt; ก็ยังไม่รู้ IP ของ &lt;code&gt;example.com&lt;&#x2F;code&gt; โดยตรง&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;แต่มันรู้ว่าโดเมนนี้ใช้ &lt;strong&gt;Nameserver ของเจ้าไหน&lt;&#x2F;strong&gt; เช่น&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;example.com → ใช้ Nameserver ns1-01.azure-dns.com
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ตรงนี้แหละครับคือ &lt;strong&gt;จุดที่ domain ของเราผูกกับ nameserver&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Domain = &lt;code&gt;example.com&lt;&#x2F;code&gt; (ที่เราจดทะเบียน)&lt;&#x2F;li&gt;
&lt;li&gt;Nameserver = &lt;code&gt;ns1-01.azure-dns.com&lt;&#x2F;code&gt; (ที่เราตั้งให้ชี้ไปยัง Azure DNS)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ถาม Nameserver ของโดเมนเรา (Azure DNS)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;คราวนี้ Resolver ก็เลยไปถาม Nameserver ของเราโดยตรง&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Azure DNS จะเปิด “สมุดของเรา” (DNS Zone) มาดูว่าเราตั้ง record อะไรไว้&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;เช่น A Record: &lt;code&gt;example.com → 20.50.100.25&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;แล้ว Azure DNS จะตอบกลับมาทันที&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Resolver ส่งคำตอบกลับไปที่ Browser&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Resolver จะเก็บคำตอบนี้ไว้ใน cache (เพื่อให้ครั้งหน้าเร็วขึ้น)&lt;&#x2F;li&gt;
&lt;li&gt;แล้วส่ง IP กลับไปให้ Browser&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Browser รู้ IP แล้ว → ไปเจอเซิร์ฟเวอร์จริง&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ได้เลข IP แล้ว Browser ก็ตรงไปหา Web Server ของเราที่ &lt;code&gt;20.50.100.25&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;สุดท้ายก็โหลดหน้าเว็บมาแสดง&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;srupdwy-diagram&quot;&gt;สรุปด้วย Diagram&lt;a class=&quot;zola-anchor&quot; href=&quot;#srupdwy-diagram&quot; aria-label=&quot;Anchor link for: srupdwy-diagram&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เราลองมาดูภาพรวมการทำงานของ DNS ผ่าน sequence diagram กันครับ&lt;&#x2F;p&gt;
&lt;pre class=&quot;mermaid&quot;&gt;
  sequenceDiagram
    participant U as User&amp;#x27;s Browser
    participant R as DNS Resolver (ISP &amp;#x2F; 8.8.8.8 &amp;#x2F; 1.1.1.1)
    participant Root as Root Server
    participant TLD as TLD Server (.com)
    participant NS as Authoritative Nameserver (Azure DNS)
    participant WS as Web Server (20.50.100.25)

    U-&amp;gt;&amp;gt;U: 1. Check local cache
    U-&amp;gt;&amp;gt;R: 2. Query example.com
    R-&amp;gt;&amp;gt;Root: 3. Ask Root for .com
    Root--&amp;gt;&amp;gt;R: Referral → TLD Server (.com)
    R-&amp;gt;&amp;gt;TLD: 4. Ask TLD for example.com
    TLD--&amp;gt;&amp;gt;R: Referral → NS (ns1-01.azure-dns.com)
    R-&amp;gt;&amp;gt;NS: 5. Ask Azure DNS for example.com
    NS--&amp;gt;&amp;gt;R: A Record → 20.50.100.25
    R--&amp;gt;&amp;gt;U: 6. Return IP 20.50.100.25
    U-&amp;gt;&amp;gt;WS: 7. Connect to Web Server
    WS--&amp;gt;&amp;gt;U: 8. Return Web Page
&lt;&#x2F;pre&gt;&lt;h3 id=&quot;srupwaa-domain-kab-nameserver-yuutrngaihn&quot;&gt;สรุปว่า Domain กับ Nameserver อยู่ตรงไหน&lt;a class=&quot;zola-anchor&quot; href=&quot;#srupwaa-domain-kab-nameserver-yuutrngaihn&quot; aria-label=&quot;Anchor link for: srupwaa-domain-kab-nameserver-yuutrngaihn&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Registrar&lt;&#x2F;strong&gt; → คือ “ร้านรับจดโดเมน” ที่เราไปซื้อชื่อเว็บ เช่น &lt;code&gt;example.com&lt;&#x2F;code&gt; ให้กลายเป็นของเรา (ตัวอย่างเช่น Metaregistrar, Namecheap, หรือ Google Domain&#x2F;Squarespace) Registrar มีหน้าที่หลัก ๆ แค่ &lt;em&gt;เก็บทะเบียนชื่อ&lt;&#x2F;em&gt; ว่าใครเป็นเจ้าของ ไม่ได้เก็บรายละเอียดว่าชื่อนี้จะต้องชี้ไปที่ไหน&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Domain&lt;&#x2F;strong&gt; → คือ “ชื่อ” ที่เราจดไว้ เช่น &lt;code&gt;example.com&lt;&#x2F;code&gt; เหมือนเราจองป้ายชื่อร้านค้าในห้าง ใครอยากเรียกร้านเราก็ต้องใช้ชื่อนี้เท่านั้น&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nameserver (NS)&lt;&#x2F;strong&gt; → คือ “สมุดโทรศัพท์ของโดเมน” ที่บันทึกกฎการชี้ทาง (DNS Record) เอาไว้ ว่าเวลามีใครเรียก &lt;code&gt;example.com&lt;&#x2F;code&gt; ต้องไปเจอ IP ไหน ใช้เมลเซิร์ฟเวอร์อะไร ฯลฯ เราเลือกเองได้ว่าจะใช้ Nameserver ของใคร เช่น Azure DNS, Cloudflare หรือ Nameserver ของ Registrar เดิม&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ดังนั้น เวลาใครถามว่า “&lt;code&gt;example.com&lt;&#x2F;code&gt; คืออะไร” → เขาจะวิ่งไปถาม &lt;strong&gt;Nameserver ที่เราตั้งไว้&lt;&#x2F;strong&gt; แล้ว Nameserver ก็จะเปิด &lt;strong&gt;DNS Zone ของเรา&lt;&#x2F;strong&gt; ขึ้นมาตอบว่า ชื่อนี้ต้องไปที่ไหนจริง ๆ ครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;khant-nkaaryaay-dns-maathii-azure-dns&quot;&gt;ขั้นตอนการย้าย DNS มาที่ Azure DNS&lt;a class=&quot;zola-anchor&quot; href=&quot;#khant-nkaaryaay-dns-maathii-azure-dns&quot; aria-label=&quot;Anchor link for: khant-nkaaryaay-dns-maathii-azure-dns&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;พอเราเข้าใจแล้วว่า Domain, Nameserver และ DNS Zone ทำงานยังไง ทีนี้มาดูภาพรวมของการย้าย DNS จากผู้ให้บริการเดิมมาที่ Azure DNS กันครับ จริง ๆ แล้วขั้นตอนไม่ซับซ้อนเลย แค่ต้องทำตามลำดับให้ถูกต้อง&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;สร้าง DNS Zone บน Azure&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;เข้า Azure Portal แล้วสร้าง Resource ประเภท &lt;em&gt;DNS Zone&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ตั้งชื่อ Zone ให้ตรงกับโดเมนที่เรามี เช่น &lt;code&gt;tt-ss-lab.com&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;understanding-dns-and-move-to-azure-dns&#x2F;create-dns-zone.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;เพิ่ม DNS Record ลงไปใน Zone&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ก๊อปปี้ Record เดิมที่มีอยู่บน DNS ของผู้ให้บริการเก่า (เช่น A, MX, CNAME, TXT) มาใส่ใน Azure DNS&lt;&#x2F;li&gt;
&lt;li&gt;ตรวจสอบให้ครบ โดยเฉพาะ record สำคัญอย่าง MX (อีเมล) และ TXT (ที่ใช้ยืนยันกับบริการต่าง ๆ)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;understanding-dns-and-move-to-azure-dns&#x2F;azure-dns-record.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;อัปเดต Nameserver ที่ Registrar&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;พอเราสร้าง Zone เสร็จ Azure จะให้ Nameserver ชุดใหม่ (เช่น &lt;code&gt;ns1-01.azure-dns.com&lt;&#x2F;code&gt;, &lt;code&gt;ns2-01.azure-dns.net&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;เข้าไปที่ Registrar ที่เราซื้อโดเมน (เช่น Google Domain&#x2F;Squarespace, Namecheap) แล้วเปลี่ยน Nameserver ของโดเมนให้ชี้ไปยัง Azure DNS&lt;&#x2F;li&gt;
&lt;li&gt;อย่างตัวอย่างนี้ผมใช้ Registrar (ผู้ให้บริการจด Domain) ในไทย และสามารถอัพเดทค่าของ nameserver จาก Azure ได้&lt;&#x2F;li&gt;
&lt;li&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;understanding-dns-and-move-to-azure-dns&#x2F;update-nameserver.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;รอ Propagation&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;หลังจากเปลี่ยน Nameserver อาจต้องรอ 24–48 ชั่วโมง กว่าข้อมูลจะอัปเดตไปทั่วโลก&lt;&#x2F;li&gt;
&lt;li&gt;ระหว่างนี้บาง resolver อาจยังตอบข้อมูลเก่าอยู่ ถือว่าเป็นเรื่องปกติ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;แค่ 4 ขั้นตอนนี้ เราก็ย้าย DNS มาจัดการเองบน Azure DNS ได้แล้วครับ ทีนี้เราจะควบคุม DNS ผ่าน Azure Portal, Azure CLI หรือ Terraform ก็ได้ สะดวกและยืดหยุ่นกว่าการผูกติดอยู่กับ DNS ของ registrar เดิมเยอะเลย&lt;&#x2F;p&gt;
&lt;p&gt;เราสามารถไปดูขั้นตอนละเอียด ๆ พร้อมภาพประกอบได้ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;dns&#x2F;dns-getstarted-portal&quot;&gt;เอกสารของ Microsoft&lt;&#x2F;a&gt; ครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;propagation-khuue-aair-thamaimt-ngr&quot;&gt;Propagation คืออะไร ทำไมต้องรอ?&lt;a class=&quot;zola-anchor&quot; href=&quot;#propagation-khuue-aair-thamaimt-ngr&quot; aria-label=&quot;Anchor link for: propagation-khuue-aair-thamaimt-ngr&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เวลาที่เราเปลี่ยน Nameserver หรือแก้ DNS Record สิ่งที่หลายคนจะเจอคือ กดบันทึกแล้วลอง &lt;code&gt;dig&lt;&#x2F;code&gt; หรือเข้าเว็บทันที ผลลัพธ์กลับเป็น &lt;strong&gt;SERVFAIL&lt;&#x2F;strong&gt; หรือยังเจอค่าของ DNS เดิมอยู่ ทั้ง ๆ ที่เราตั้งค่าใหม่เรียบร้อยแล้ว …จริง ๆ แล้วนี่คือเรื่องปกติครับ เพราะมันเกี่ยวกับสิ่งที่เรียกว่า &lt;strong&gt;DNS Propagation&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ลองนึกภาพว่า DNS ไม่ได้เก็บอยู่ที่เซิร์ฟเวอร์กลางแค่จุดเดียว แต่เป็น &lt;strong&gt;สมุดโทรศัพท์ที่กระจายอยู่ทั่วโลก&lt;&#x2F;strong&gt; ไม่ว่าจะเป็น resolver ของ ISP, ของ Google, ของ Cloudflare หรือขององค์กรต่าง ๆ แต่ละที่ก็จะเก็บ “สำเนา” ของสมุดไว้ใน cache ของตัวเอง และแต่ละ record จะมีอายุการเก็บกำหนดโดยค่า &lt;strong&gt;TTL (Time To Live)&lt;&#x2F;strong&gt; เช่น 300 วินาที (5 นาที), 3600 วินาที (1 ชั่วโมง) หรือบางครั้งยาวเป็นวัน&lt;&#x2F;p&gt;
&lt;p&gt;เมื่อเรามีการเปลี่ยน DNS Record → ข้อมูลใหม่จะถูกบันทึกที่ Nameserver ของเรา (เช่น Azure DNS) ทันที แต่ resolver ที่อื่น ๆ ทั่วโลกอาจยังเก็บค่าของ record เก่าไว้ใน cache จนกว่า TTL จะหมด ถึงตอนนั้น resolver ถึงจะกลับไปถาม Nameserver ของเราอีกครั้ง แล้วค่อยอัปเดตค่าใหม่&lt;&#x2F;p&gt;
&lt;h3 id=&quot;srupaihekhaaaicchngaay&quot;&gt;สรุปให้เข้าใจง่าย ๆ&lt;a class=&quot;zola-anchor&quot; href=&quot;#srupaihekhaaaicchngaay&quot; aria-label=&quot;Anchor link for: srupaihekhaaaicchngaay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;DNS ทำงานแบบกระจายศูนย์ → ไม่มีที่เก็บกลาง ทุก resolver มีสำเนาของตัวเอง&lt;&#x2F;li&gt;
&lt;li&gt;ค่า &lt;strong&gt;TTL&lt;&#x2F;strong&gt; คือกำหนดว่า “ข้อมูลเก่านี้จะใช้ได้นานแค่ไหน”&lt;&#x2F;li&gt;
&lt;li&gt;ระหว่าง propagation (24–48 ชั่วโมงในกรณีเปลี่ยน Nameserver) → บางที่อาจตอบข้อมูลใหม่แล้ว แต่บางที่ยังตอบข้อมูลเก่าอยู่&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ดังนั้นเวลาที่เพิ่งย้าย DNS มาที่ Azure แล้วเจอว่าเว็บยังเข้าไม่ได้ อย่าเพิ่งตกใจไปครับ ส่วนใหญ่ไม่ใช่ตั้งค่าผิด แต่เป็นเพราะ propagation กำลังทำงานอยู่ รอให้ cache ทั่วโลกหมดอายุแล้วข้อมูลใหม่จะแพร่กระจายไปครบเอง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;krniisueksaakh-ngcchring-yaayodemnaip-azure-dns-aelwecch-servfail&quot;&gt;กรณีศึกษาของจริง: ย้ายโดเมนไป Azure DNS แล้วเจอ SERVFAIL&lt;a class=&quot;zola-anchor&quot; href=&quot;#krniisueksaakh-ngcchring-yaayodemnaip-azure-dns-aelwecch-servfail&quot; aria-label=&quot;Anchor link for: krniisueksaakh-ngcchring-yaayodemnaip-azure-dns-aelwecch-servfail&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ตอนที่ผมย้ายโดเมน &lt;code&gt;tt-ss-lab.com&lt;&#x2F;code&gt; มาที่ Azure DNS สิ่งแรกที่ทำหลังจากเปลี่ยน Nameserver ที่ registrar ก็คือรีบลอง &lt;code&gt;dig&lt;&#x2F;code&gt; เพื่อเช็กผลลัพธ์ แต่สิ่งที่เจอคือทุก query กลับมาตอบว่า&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;status: SERVFAIL
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ตอนนั้นผมก็คิดว่าต้องตั้งค่าผิดแน่ ๆ เพราะลองถามทั้ง &lt;code&gt;A&lt;&#x2F;code&gt;, &lt;code&gt;MX&lt;&#x2F;code&gt;, &lt;code&gt;CNAME&lt;&#x2F;code&gt;, &lt;code&gt;TXT&lt;&#x2F;code&gt; ก็ยัง FAIL เหมือนเดิมทั้งหมด&lt;&#x2F;p&gt;
&lt;p&gt;แต่พอลองไล่เช็กไปทีละขั้นก็เจอสาเหตุจริง ๆ อยู่สองข้อ:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Propagation ยังไม่เสร็จ&lt;&#x2F;strong&gt;
หลังเปลี่ยน Nameserver ข้อมูลยังไม่กระจายไปทั่วโลก resolver ของ ISP ที่ใช้ยังชี้ไป Nameserver เก่า เลยตอบกลับด้วย error&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Zone ใน Azure ยังว่างเปล่า&lt;&#x2F;strong&gt;
ถึง Nameserver ใหม่จะถูกเปลี่ยนเรียบร้อยแล้ว แต่ DNS Zone ของผมยังไม่มี record พื้นฐานเลย พอ resolver ภายนอกถามมาก็เลย “ไม่มีคำตอบจะตอบกลับ” → กลายเป็น SERVFAIL&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;withiiaek&quot;&gt;วิธีแก้&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiiaek&quot; aria-label=&quot;Anchor link for: withiiaek&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ผมลองถามตรงไปที่ Nameserver ของ Azure โดยใช้คำสั่ง:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; CNAME test-azure.tt-ss-lab.com @ns1-01.azure-dns.com&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;คราวนี้ได้คำตอบกลับมาทันที ว่า &lt;code&gt;test-azure.tt-ss-lab.com&lt;&#x2F;code&gt; ชี้ไปยัง &lt;code&gt;chaiyo-ca.jollyplant...azurecontainerapps.io&lt;&#x2F;code&gt; แสดงว่า Zone ทำงานปกติแล้ว&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;นอกจากนี้ ผมลองใช้ &lt;code&gt;nslookup&lt;&#x2F;code&gt; แทน &lt;code&gt;dig&lt;&#x2F;code&gt; ก็ได้คำตอบกลับมาจาก resolver อีกตัวหนึ่งเร็วกว่า (non-authoritative answer) ทำให้มั่นใจได้ว่าค่าถูกต้อง เพียงแต่ propagation บาง resolver ยังไม่อัปเดต&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;สรุปแล้วปัญหามาจาก &lt;strong&gt;Propagation ที่ยังไม่เสร็จ + ไม่มี record พื้นฐาน (A, MX, TXT)&lt;&#x2F;strong&gt; ใน Zone นั่นเอง&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;hlangcchaaktrwcchs-bdwy-nslookup&quot;&gt;หลังจากตรวจสอบด้วย nslookup&lt;a class=&quot;zola-anchor&quot; href=&quot;#hlangcchaaktrwcchs-bdwy-nslookup&quot; aria-label=&quot;Anchor link for: hlangcchaaktrwcchs-bdwy-nslookup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;หลังจากที่ผมลอง &lt;code&gt;nslookup&lt;&#x2F;code&gt; แล้วเริ่มเห็นข้อมูล CNAME ของ &lt;code&gt;test-azure.tt-ss-lab.com&lt;&#x2F;code&gt; ชี้ไปที่ Azure Container App ได้ถูกต้อง ผมก็ไปลองขั้นตอนถัดไปทันที คือ &lt;strong&gt;ผูก Custom Domain&lt;&#x2F;strong&gt; บน Azure Container App&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ nslookup test-azure.tt-ss-lab.com
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;;; Got SERVFAIL reply from 2001:fb0:100::207:49, trying next server
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Server:		2001:fb0:100::207:29
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Address:	2001:fb0:100::207:29#53
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Non-authoritative answer:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;test-azure.tt-ss-lab.com	canonical name = chaiyo-ca.jollyplant-effa115b.southeastasia.azurecontainerapps.io.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Name:	chaiyo-ca.jollyplant-effa115b.southeastasia.azurecontainerapps.io
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Address: 40.119.236.238
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ผลลัพธ์คือ Azure สามารถ &lt;strong&gt;validate domain ผ่านได้เลย&lt;&#x2F;strong&gt; เพราะมันเห็นว่า CNAME record ถูกต้องแล้ว หลังจากนั้นก็สามารถผูก &lt;code&gt;test-azure.tt-ss-lab.com&lt;&#x2F;code&gt; เข้ากับ Container App ของผมได้สำเร็จ โดยไม่ต้องรอ propagation ครบทุก resolver ด้วยซ้ำ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;understanding-dns-and-move-to-azure-dns&#x2F;add-custom-domain.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;นี่ทำให้เห็นว่า บางครั้งแม้เราจะเจอ SERVFAIL จาก &lt;code&gt;dig&lt;&#x2F;code&gt; แต่ถ้าลองเช็กด้วย &lt;code&gt;nslookup&lt;&#x2F;code&gt; หรือ query ตรงไปยัง Nameserver ของ Azure ก็อาจได้คำตอบที่ใช้ได้ทันที และสามารถดำเนินการต่อใน Azure ได้เลย&lt;&#x2F;p&gt;
&lt;h3 id=&quot;btheriiynthiiaid&quot;&gt;บทเรียนที่ได้&lt;a class=&quot;zola-anchor&quot; href=&quot;#btheriiynthiiaid&quot; aria-label=&quot;Anchor link for: btheriiynthiiaid&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;หลังเปลี่ยน Nameserver &lt;strong&gt;อย่าเพิ่งรีบเทสทันที&lt;&#x2F;strong&gt; ให้เวลา propagation อย่างน้อย 24–48 ชั่วโมง แต่อาจจะเสร็จเร็วกว่านั้นได้&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ตรวจสอบว่า Zone ของเรามี record พื้นฐานครบแล้ว โดยเฉพาะ A record สำหรับ root domain&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เวลาเจอ SERVFAIL ให้ลองสองวิธี:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ถามตรงไปที่ Nameserver ของ Azure (&lt;code&gt;@ns1-01.azure-dns.com&lt;&#x2F;code&gt;) → ถ้าได้ผลลัพธ์ แสดงว่า Zone ปกติ&lt;&#x2F;li&gt;
&lt;li&gt;ใช้ &lt;code&gt;nslookup&lt;&#x2F;code&gt; เช็กกับ resolver ตัวอื่น เผื่อได้คำตอบ non-authoritative ที่ confirm ค่าใหม่ได้เร็วกว่า&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ตรงนี้จะช่วยให้คนอ่านมั่นใจว่า ถึง propagation จะยังไม่ครบ แต่เราก็สามารถ &lt;strong&gt;validate domain และผูก Custom Domain บน Azure&lt;&#x2F;strong&gt; ได้ตั้งแต่เนิ่น ๆ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ekhruue-ngmuue-command-line-samhrabtrwcchs-b-dns&quot;&gt;เครื่องมือ Command Line สำหรับตรวจสอบ DNS&lt;a class=&quot;zola-anchor&quot; href=&quot;#ekhruue-ngmuue-command-line-samhrabtrwcchs-b-dns&quot; aria-label=&quot;Anchor link for: ekhruue-ngmuue-command-line-samhrabtrwcchs-b-dns&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เวลาที่เราย้ายโดเมนหรือแก้ไข DNS การตรวจสอบด้วย command line จะช่วยให้เราเห็นว่าระบบตอบสนองยังไงบ้าง ผมขอสรุปเป็น 5 คำสั่งหลัก ๆ ที่ใช้บ่อยครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-dig&quot;&gt;1. &lt;code&gt;dig&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-dig&quot; aria-label=&quot;Anchor link for: 1-dig&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; A example.com&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; CNAME test-azure.example.com&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; MX example.com&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;ใช้ถาม DNS Record โดยตรง เช่น A, CNAME, MX, TXT&lt;&#x2F;li&gt;
&lt;li&gt;แสดงผลละเอียด เช่น TTL, authority, server ที่ตอบ&lt;&#x2F;li&gt;
&lt;li&gt;ถ้าเจอ &lt;code&gt;status: SERVFAIL&lt;&#x2F;code&gt; → แสดงว่า resolver ที่ถามยังไม่รู้จัก record นี้ (อาจเป็นเพราะ propagation ยังไม่เสร็จ)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;2-dig-nameserver&quot;&gt;2. &lt;code&gt;dig @nameserver&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-dig-nameserver&quot; aria-label=&quot;Anchor link for: 2-dig-nameserver&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; CNAME test-azure.example.com @ns1-01.azure-dns.com&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;ใช้ถามตรงไปยัง &lt;strong&gt;Authoritative Nameserver&lt;&#x2F;strong&gt; ของโดเมน เช่น Azure DNS&lt;&#x2F;li&gt;
&lt;li&gt;จะได้คำตอบตรงจาก DNS Zone ของเรา ไม่ต้องรอ propagation&lt;&#x2F;li&gt;
&lt;li&gt;เหมาะมากเวลาอยากเช็กว่า record ที่สร้างไว้ใน Zone ทำงานแล้วหรือยัง&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;3-nslookup&quot;&gt;3. &lt;code&gt;nslookup&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-nslookup&quot; aria-label=&quot;Anchor link for: 3-nslookup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nslookup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; example.com&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nslookup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; test-azure.example.com&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;ใช้ง่ายกว่า &lt;code&gt;dig&lt;&#x2F;code&gt; และมักจะตอบว่า &lt;strong&gt;Non-authoritative answer&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;หมายความว่า: คำตอบมาจาก &lt;strong&gt;resolver ตัวกลาง&lt;&#x2F;strong&gt; (เช่น DNS ของ ISP, Google 8.8.8.8, Cloudflare 1.1.1.1) ที่เก็บข้อมูลไว้ใน cache → ไม่ได้ตอบจาก Nameserver ต้นทาง&lt;&#x2F;li&gt;
&lt;li&gt;ข้อดี: บางครั้ง resolver บางตัวอัปเดตเร็ว ทำให้เห็นผล propagation ได้ก่อนที่ resolver อื่น ๆ จะตามทัน&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;4-whois&quot;&gt;4. &lt;code&gt;whois&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-whois&quot; aria-label=&quot;Anchor link for: 4-whois&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;whois&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; example.com&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;ใช้ดูข้อมูลการจดทะเบียนโดเมน&lt;&#x2F;li&gt;
&lt;li&gt;บอกได้ว่า registrar คือใคร, วันหมดอายุ, และ &lt;strong&gt;Nameserver ปัจจุบัน&lt;&#x2F;strong&gt; ของโดเมนคืออะไร&lt;&#x2F;li&gt;
&lt;li&gt;ช่วยเช็กได้ว่าเราส่งค่า Nameserver ไปที่ Azure DNS แล้วหรือยัง&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;5-host-iikthaangeluue-k&quot;&gt;5. &lt;code&gt;host&lt;&#x2F;code&gt; (อีกทางเลือก)&lt;a class=&quot;zola-anchor&quot; href=&quot;#5-host-iikthaangeluue-k&quot; aria-label=&quot;Anchor link for: 5-host-iikthaangeluue-k&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;host&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; example.com&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;ผลลัพธ์สั้น กระชับกว่า &lt;code&gt;dig&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;เหมาะสำหรับการตรวจสอบเร็ว ๆ เช่นดูว่า domain resolve ไปที่ IP ไหน&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;authoritative-vs-non-authoritative&quot;&gt;Authoritative vs Non-authoritative&lt;a class=&quot;zola-anchor&quot; href=&quot;#authoritative-vs-non-authoritative&quot; aria-label=&quot;Anchor link for: authoritative-vs-non-authoritative&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Authoritative Answer&lt;&#x2F;strong&gt; → มาจาก Nameserver ต้นทางของโดเมนโดยตรง (เช่น Azure DNS) → เป็นข้อมูลจริงล่าสุด 100%&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Non-authoritative Answer&lt;&#x2F;strong&gt; → มาจาก cache ของ resolver ตัวกลาง (เช่น DNS ของ ISP หรือ Google DNS) → เร็วกว่า แต่บางครั้งอาจยังเป็นข้อมูลเก่า&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;ul&gt;
&lt;li&gt;📌 ถ้าอยากเช็กว่าค่าใน DNS Zone ถูกต้องแล้ว → ใช้ &lt;code&gt;dig @ns1-01.azure-dns.com&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;📌 ถ้าอยากดูว่าค่าเริ่มเผยแพร่ไปทั่วโลกแล้วหรือยัง → ใช้ &lt;code&gt;nslookup&lt;&#x2F;code&gt; หรือ &lt;code&gt;dig&lt;&#x2F;code&gt; ธรรมดา (ไม่ระบุ nameserver)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;การใช้คำสั่งเหล่านี้ร่วมกัน จะช่วยให้เราแยกปัญหาได้ทันทีว่า:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;โดเมนยังไม่เปลี่ยน nameserver ที่ registrar&lt;&#x2F;li&gt;
&lt;li&gt;Zone บน Azure DNS ยังไม่มี record&lt;&#x2F;li&gt;
&lt;li&gt;หรือ propagation ยังไม่เสร็จ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;odysrup&quot;&gt;โดยสรุป&lt;a class=&quot;zola-anchor&quot; href=&quot;#odysrup&quot; aria-label=&quot;Anchor link for: odysrup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;DNS ฟังดูเป็นเรื่องซับซ้อน แต่ถ้าเราเปรียบเทียบให้ง่าย ๆ ว่า &lt;strong&gt;Domain คือชื่อร้าน&lt;&#x2F;strong&gt;, &lt;strong&gt;IP คือเบอร์โทรศัพท์&lt;&#x2F;strong&gt;, และ &lt;strong&gt;DNS คือสมุดโทรศัพท์ของอินเทอร์เน็ต&lt;&#x2F;strong&gt; ทุกอย่างก็จะเริ่มชัดขึ้นทันที&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;เวลาเราซื้อโดเมนจาก registrar → เราได้ทั้ง “ชื่อร้าน” (domain) และ “สมุดโทรศัพท์เบื้องต้น” (DNS record ที่แถมมา)&lt;&#x2F;li&gt;
&lt;li&gt;ถ้าอยากควบคุมเองมากขึ้น เช่น ใช้ Azure App Service, Container App หรือจัดการ DNS ด้วยโค้ด (Terraform&#x2F;CLI) → เราก็แค่เปลี่ยน Nameserver ไปที่ Azure DNS&lt;&#x2F;li&gt;
&lt;li&gt;เมื่อเปลี่ยนแล้ว บางครั้งเจอปัญหา &lt;strong&gt;SERVFAIL&lt;&#x2F;strong&gt; ซึ่งส่วนใหญ่เกิดจาก propagation ที่ยังไม่เสร็จ หรือ Zone ยังไม่มี record พื้นฐาน ไม่ได้แปลว่าตั้งค่าผิด&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;การตรวจสอบด้วย command line อย่าง &lt;code&gt;dig&lt;&#x2F;code&gt;, &lt;code&gt;nslookup&lt;&#x2F;code&gt;, &lt;code&gt;whois&lt;&#x2F;code&gt; ช่วยให้เรารู้ได้ทันทีว่า ปัญหาอยู่ตรงไหนกันแน่ และไม่ต้องนั่งเดาแบบงง ๆ อีกต่อไป&lt;&#x2F;p&gt;
&lt;h3 id=&quot;khamsrupsamkhay-key-takeaways&quot;&gt;คำสรุปสำคัญ (Key Takeaways)&lt;a class=&quot;zola-anchor&quot; href=&quot;#khamsrupsamkhay-key-takeaways&quot; aria-label=&quot;Anchor link for: khamsrupsamkhay-key-takeaways&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;DNS Zone = สมุดโทรศัพท์&lt;&#x2F;strong&gt; ของโดเมน → เราสามารถเลือกจะฝากสมุดนี้ไว้กับใครก็ได้ เช่น Azure DNS, Cloudflare หรือ registrar เดิม&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Authoritative vs Non-authoritative&lt;&#x2F;strong&gt; → ถามตรง Nameserver = ได้ข้อมูลจริงล่าสุด, ถาม resolver ทั่วไป = ได้ข้อมูลจาก cache&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Propagation ต้องใช้เวลา&lt;&#x2F;strong&gt; → 24–48 ชั่วโมงเป็นเรื่องปกติ อย่าเพิ่งตกใจถ้าเจอ SERVFAIL&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;เช็กด้วยเครื่องมือ&lt;&#x2F;strong&gt; → &lt;code&gt;dig @nsX-azure-dns.com&lt;&#x2F;code&gt; เพื่อตรวจสอบ Zone โดยตรง, &lt;code&gt;nslookup&lt;&#x2F;code&gt; เพื่อตรวจสอบการเผยแพร่&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;thingthaay&quot;&gt;ทิ้งท้าย&lt;a class=&quot;zola-anchor&quot; href=&quot;#thingthaay&quot; aria-label=&quot;Anchor link for: thingthaay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;พอเราเข้าใจภาพรวมแล้ว DNS จะไม่ใช่ “กล่องดำลึกลับ” อีกต่อไปครับ การย้ายโดเมนมาที่ Azure DNS ก็ไม่ได้ซับซ้อนอย่างที่คิด — แค่เปลี่ยน nameserver, ย้าย record มาครบ, รอ propagation ให้เสร็จ แล้วทุกอย่างก็พร้อมใช้งาน&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าเคยรู้สึกว่า DNS เป็นเรื่องยาก ลองกลับมาอ่านบทความนี้อีกครั้ง คุณจะเห็นว่า จริง ๆ แล้วมันก็แค่ “การเปิดสมุดโทรศัพท์ → หาว่าชื่อนี้ต้องไปเบอร์ไหน” เท่านั้นเอง ✨&lt;&#x2F;p&gt;
&lt;p&gt;ไว้เจอกันใหม่บทความหน้านะ สวัสดีครับ 👋&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ลงมือจริง: Setup Actual Budget บน VM ด้วย Docker, Nginx และ Cloudflare - EP2</title>
		<published>2025-08-31T00:00:00+00:00</published>
		<updated>2025-08-31T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/ep2-setup-actual-budget-vm-docker-nginx-cloudflare/" type="text/html"/>
		<id>https://thadaw.com/posts/ep2-setup-actual-budget-vm-docker-nginx-cloudflare/</id>
		<content type="html">&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;Series SSL&amp;#x2F;TLS กับ Cloudflare&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;ul&gt;
&lt;li&gt;EP 1: &lt;a href=&quot;&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;&quot;&gt;เข้าใจ SSL&#x2F;TLS แบบง่าย ๆ ผ่าน Cloudflare และ Azure&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;EP 2: ลงมือจริง: Setup Actual Budget บน VM ด้วย Docker, Nginx และ Cloudflare (บทความนี้)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;สวัสดีครับ วันนี้ก็จะมาต่อกันใน &lt;strong&gt;EP2&lt;&#x2F;strong&gt; ของซีรีส์ SSL&#x2F;TLS ที่เราเริ่มไว้กันนะครับ ถ้าใครได้อ่านตอนแรกไปแล้วก็น่าจะพอเห็นภาพกว้าง ๆ ว่า HTTPS มันทำงานยังไง ผ่านตัวอย่าง Cloudflare กับ Azure ว่าเวลาเราเลือกใช้ Managed Service หรือ VM เองเนี่ย เรื่องของ certificate จะต่างกันยังไง แต่พอเข้าใจแล้ว คราวนี้เราจะลอง “ลงมือจริง” กันดูบ้างครับ&lt;&#x2F;p&gt;
&lt;p&gt;ใน EP2 นี้ ผมจะเอาโปรเจกต์เล็ก ๆ ที่ชื่อว่า &lt;strong&gt;Actual Budget&lt;&#x2F;strong&gt; ซึ่งเป็น open-source budgeting app มาเป็นตัวอย่าง สมมติว่าเราอยากจะทำให้มันออนไลน์ใช้งานได้จริงบน VM ของเราเอง แล้วก็ครอบมันด้วย &lt;strong&gt;Nginx + Cloudflare Origin Certificate&lt;&#x2F;strong&gt; เพื่อให้ทุกอย่างปลอดภัยภายใต้โหมด Full (Strict) กันครับ เป้าหมายก็คือ… จาก VM ที่ว่างเปล่า เราจะค่อย ๆ ทำให้มันกลายเป็นเว็บที่มี HTTPS พร้อมใช้งานได้จริง ✨&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;callout tip&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M9.97308 18H11V13H13V18H14.0269C14.1589 16.7984 14.7721 15.8065 15.7676 14.7226C15.8797 14.6006 16.5988 13.8564 16.6841 13.7501C17.5318 12.6931 18 11.385 18 10C18 6.68629 15.3137 4 12 4C8.68629 4 6 6.68629 6 10C6 11.3843 6.46774 12.6917 7.31462 13.7484C7.40004 13.855 8.12081 14.6012 8.23154 14.7218C9.22766 15.8064 9.84103 16.7984 9.97308 18ZM10 20V21H14V20H10ZM5.75395 14.9992C4.65645 13.6297 4 11.8915 4 10C4 5.58172 7.58172 2 12 2C16.4183 2 20 5.58172 20 10C20 11.8925 19.3428 13.6315 18.2443 15.0014C17.624 15.7748 16 17 16 18.5V21C16 22.1046 15.1046 23 14 23H10C8.89543 23 8 22.1046 8 21V18.5C8 17 6.37458 15.7736 5.75395 14.9992Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;Source Code&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;p&gt;สำหรับใครที่อยากลองทำตาม สามารถดูตัวอย่าง config ทั้งหมดได้ที่ GitHub repo นี้ครับ: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;actualbudget-vm-cloudflare&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;actualbudget-vm-cloudflare&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ก่อนหน้านี้ผมเองก็เคยได้มีโอกาสลองใช้ &lt;strong&gt;YNAB (You Need A Budget)&lt;&#x2F;strong&gt; ในการจัดการเรื่องการเงินและงบประมาณส่วนตัว ต้องบอกเลยว่ามันเปลี่ยนวิธีคิดเรื่องการเงินของผมไปพอสมควร ปัญหาที่เคยเจอกันบ่อย ๆ อย่าง “เงินหายไปไหน”, “วางแผนงบยังไงดี”, หรือ “ค่าใช้จ่ายจริงกับที่ตั้งงบไม่ตรงกัน” — พอมาใช้ YNAB แล้วกลับกลายเป็นเรื่องที่ &lt;strong&gt;ง่ายขึ้นเยอะมาก&lt;&#x2F;strong&gt; เพราะตัวแอปมันออกแบบมาให้เราโฟกัสกับการบอก “ทุกบาททุกสตางค์มีที่ไป”&lt;&#x2F;p&gt;
&lt;p&gt;แต่ข้อเสียก็คือ ราคามันสูงไปหน่อยสำหรับการใช้งานระยะยาวสำหรับผม 😅 จนสุดท้ายผมมาเจอโปรเจกต์ที่ชื่อว่า &lt;strong&gt;Actual Budget&lt;&#x2F;strong&gt; ซึ่งเป็น open-source ที่หยิบเอาแนวคิดเดียวกันมาทำให้ฟรี และเราสามารถโฮสต์เองได้ ใครที่อยากเริ่มทำ “บัญชีส่วนตัว” แบบจริงจัง ผมแนะนำเลยครับว่าลอง Actual Budget ได้เลย จะเลือกใช้ VM บน Azure, DigitalOcean, fly.io หรือเจ้าไหนก็แล้วแต่ถนัดเลย แต่ในบทความนี้ผมจะขอใช้ &lt;strong&gt;Azure VM&lt;&#x2F;strong&gt; เป็นตัวอย่างหลักในการสาธิตครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1-etriiym-vm&quot;&gt;1. เตรียม VM&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-etriiym-vm&quot; aria-label=&quot;Anchor link for: 1-etriiym-vm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;สมมติว่าเรากำลังจะสร้างบ้านสักหลัง สิ่งแรกที่ต้องมีเลยก็คือ “ที่ดินเปล่า” ให้เราลงเสาเข็มได้ถูกไหมครับ? โลกของเซิร์ฟเวอร์ก็ไม่ต่างกันเลย สิ่งแรกที่เราต้องมีคือ &lt;strong&gt;VM เปล่า ๆ&lt;&#x2F;strong&gt; ซึ่งจะเป็นเหมือนที่ดินที่เราจะเอาบ้าน (หรือแอป Actual Budget ของเรา) ไปลงบนมัน&lt;&#x2F;p&gt;
&lt;p&gt;ในตัวอย่างนี้ผมจะใช้ &lt;strong&gt;Azure VM&lt;&#x2F;strong&gt; เป็นหลัก แต่จริง ๆ คุณจะเลือก DigitalOcean, AWS หรือเจ้าอื่นก็ได้เหมือนกัน ขึ้นอยู่กับความถนัดและความสะดวกของแต่ละคนเลยครับ จุดสำคัญคือ VM นี้จะต้องเป็น Linux (Ubuntu 20.04&#x2F;22.04) ซึ่งเป็นเหมือน “ดินคุณภาพดี” ที่พร้อมให้เราลงโครงสร้างต่อไปได้ง่าย ๆ&lt;&#x2F;p&gt;
&lt;p&gt;พอได้ VM แล้ว เราก็เข้าไปผ่าน SSH เหมือนเดินเข้าสำรวจที่ดินของเรา จากนั้นกวาดลานนิดหน่อย (update system) เพื่อเคลียร์สภาพแวดล้อมให้พร้อมจะลงของใหม่ครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thamaimt-ngaich-vm-aimaich-managed-service&quot;&gt;ทำไมต้องใช้ VM ไม่ใช้ Managed Service?&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaimt-ngaich-vm-aimaich-managed-service&quot; aria-label=&quot;Anchor link for: thamaimt-ngaich-vm-aimaich-managed-service&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;หลายคนอาจสงสัยว่า… ทำไมเราต้องไปยุ่งยากเช่า VM เอง ทั้ง ๆ ที่ Azure หรือ Cloud Provider อื่น ๆ ก็มีพวก Managed Service ที่ทำให้ชีวิตง่ายขึ้น เช่น Azure App Service, Azure Container App อะไรพวกนี้ที่แถม HTTPS มาให้เลย แต่เหตุผลหลัก ๆ มันอยู่ตรงนี้ครับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Actual Budget ใช้ SQLite เป็นฐานข้อมูลหลัก&lt;&#x2F;strong&gt; ซึ่ง SQLite จะเขียนไฟล์ลงดิสก์โดยตรง เวลาแอปทำงานจริง มันต้องการ &lt;strong&gt;mount volume แบบ native&lt;&#x2F;strong&gt; เพื่อให้สามารถอ่าน–เขียนไฟล์ได้ตามปกติ&lt;&#x2F;p&gt;
&lt;p&gt;ปัญหาคือ Managed Service ส่วนใหญ่ โดยเฉพาะพวก PaaS (Platform-as-a-Service) ของ Azure จะให้เราใช้ &lt;strong&gt;Azure Files&lt;&#x2F;strong&gt; หรือ storage อื่น ๆ ที่เป็น network file system แทน ซึ่งมันไม่ได้ support พฤติกรรมการเขียนไฟล์ทั้งหมดของ SQLite แบบ 100% ผลลัพธ์คือ… พอเราไป deploy จริง เราจะเจอ error ประมาณนี้เลย:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[Error: PRAGMA journal_mode = WAL - SQLITE_BUSY: database is locked]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ซึ่งก็คือ SQLite พยายามเข้าโหมด WAL (Write-Ahead Logging) แต่ดันล็อกไฟล์ไม่ได้ เพราะ storage ไม่รองรับการทำงานแบบนั้นเต็ม ๆ&lt;&#x2F;p&gt;
&lt;p&gt;ตรงนี้แหละครับที่ทำให้เราต้องเลือกใช้ &lt;strong&gt;VM&lt;&#x2F;strong&gt; หรือ service ที่ support &lt;strong&gt;native filesystem mount&lt;&#x2F;strong&gt; ได้จริง ๆ เช่น Azure VM, DigitalOcean Droplet, หรือ AWS EC2 เป็นต้น เพื่อให้ SQLite ทำงานได้ถูกต้องโดยไม่มีปัญหาเรื่อง database lock&lt;&#x2F;p&gt;
&lt;p&gt;พูดง่าย ๆ คือ… ถ้าเราอยากให้ Actual Budget รันได้ลื่น ๆ แบบไม่ต้องมานั่งปวดหัวกับ error แปลก ๆ เราก็ต้องยอมไปเช่า VM มา แล้วจัดการ environment เองทั้งหมดครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-tidtang-docker-docker-compose&quot;&gt;2. ติดตั้ง Docker &amp;amp; Docker Compose&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-tidtang-docker-docker-compose&quot; aria-label=&quot;Anchor link for: 2-tidtang-docker-docker-compose&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;พอเราได้ VM ที่เหมือนที่ดินเปล่า ๆ มาแล้ว ขั้นต่อไปก็คือการ “สร้างบ้าน” ให้แอปของเราอยู่ได้จริง แต่แทนที่จะไปลงเสา เทปูน ก่ออิฐทีละก้อน (ลง dependency เอง, ติดตั้ง runtime เอง) …เราจะเลือกวิธีที่ง่ายกว่า ก็คือการยก &lt;strong&gt;บ้านสำเร็จรูป&lt;&#x2F;strong&gt; มาลงไปเลยครับ&lt;&#x2F;p&gt;
&lt;p&gt;บ้านสำเร็จรูปในโลกของเซิร์ฟเวอร์ก็คือ &lt;strong&gt;Docker&lt;&#x2F;strong&gt; นั่นเอง — เราสามารถแพ็ก Actual Budget, Nginx, และ service อื่น ๆ ไว้ใน container ที่พร้อมใช้งาน แล้วเอามาวางลงบน VM ของเราได้ทันที โดยไม่ต้องห่วงว่า dependency จะชนกันหรือติดตั้งผิดเวอร์ชัน&lt;&#x2F;p&gt;
&lt;p&gt;นอกจากนี้ เรายังมี &lt;strong&gt;Docker Compose&lt;&#x2F;strong&gt; เป็นเหมือนแปลนบ้าน ที่เราบอกไว้เลยว่า “ห้องนี้คือ Nginx, ห้องนี้คือ Actual Budget, ห้องนี้ต่อไฟเข้ากับ database” — ทุกอย่างถูกนิยามไว้ในไฟล์ &lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt; พอเราสั่ง &lt;code&gt;docker compose up -d&lt;&#x2F;code&gt; มันก็จะยกบ้านทั้งหลังขึ้นมาให้เราแบบอัตโนมัติเลย&lt;&#x2F;p&gt;
&lt;p&gt;ดังนั้นก่อนที่เราจะไปตั้งค่า config อื่น ๆ สิ่งแรกที่ต้องทำใน VM ของเราคือ:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;ติดตั้ง Docker&lt;&#x2F;li&gt;
&lt;li&gt;ติดตั้ง Docker Compose&lt;&#x2F;li&gt;
&lt;li&gt;ตรวจสอบว่าใช้งานได้จริง (&lt;code&gt;docker --version&lt;&#x2F;code&gt;, &lt;code&gt;docker compose version&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;เมื่อเสร็จแล้ว เราก็พร้อมที่จะ “เอาของไปลงบ้าน” ได้ทันที&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3-config-environment-samhrab-actual-budget&quot;&gt;3. Config Environment สำหรับ Actual Budget&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-config-environment-samhrab-actual-budget&quot; aria-label=&quot;Anchor link for: 3-config-environment-samhrab-actual-budget&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;โอเคครับ ตอนนี้เรามี VM (ที่ดิน) + Docker&#x2F;Compose (บ้านสำเร็จรูป) พร้อมแล้ว ทีนี้ก็ถึงเวลามา &lt;strong&gt;จัดห้อง จัดเฟอร์นิเจอร์&lt;&#x2F;strong&gt; ภายในบ้านกัน&lt;&#x2F;p&gt;
&lt;p&gt;สำหรับ Actual Budget สิ่งที่เราต้องทำก็คือการ &lt;strong&gt;ตั้งค่า environment&lt;&#x2F;strong&gt; เพื่อบอกบ้านเราว่า “ห้องไหนทำหน้าที่อะไร” เช่น URL ของเว็บ, ชื่อโดเมน, และ proxy ที่ไว้รับ request จากข้างนอก&lt;&#x2F;p&gt;
&lt;p&gt;วิธีการก็ง่าย ๆ ครับ:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;เรา clone หรือโหลด template โปรเจกต์จาก GitHub มาก่อน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;actualbudget-vm-cloudflare&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;actualbudget-vm-cloudflare&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;จากนั้น copy ไฟล์ &lt;code&gt;.env.example&lt;&#x2F;code&gt; มาเป็น &lt;code&gt;.env&lt;&#x2F;code&gt; เหมือนเราได้คู่มือบ้านมาหนึ่งชุด&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เปิด &lt;code&gt;.env&lt;&#x2F;code&gt; แล้วปรับค่าให้ตรงกับของเรา เช่น:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ACTUAL_BASE_URL=https:&#x2F;&#x2F;actual-budget.mydomain.com&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;ACTUAL_SERVER_HOSTNAME=actual-budget.mydomain.com&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;TRUSTED_PROXIES&lt;&#x2F;code&gt; (ใครที่เรายอมให้ผ่าน proxy ได้)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;นอกจากนี้ยังต้องไปแก้ใน config ของ Nginx (&lt;code&gt;default.conf&lt;&#x2F;code&gt;) ให้ใช้โดเมนของเราจริง ๆ ด้วย เพื่อให้เวลามีคนพิมพ์ &lt;code&gt;https:&#x2F;&#x2F;actual-budget.mydomain.com&lt;&#x2F;code&gt; ระบบจะรู้จักและส่งไปหา container ที่ถูกต้อง&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;พูดง่าย ๆ ก็คือ ขั้นตอนนี้คือการ &lt;strong&gt;จัดห้อง + ตั้งป้ายชื่อห้อง&lt;&#x2F;strong&gt; ว่า “อันนี้ห้องครัวนะ, อันนี้ห้องนั่งเล่นนะ” เพื่อให้ระบบทั้งหมดมันสื่อสารกันถูกต้อง&lt;&#x2F;p&gt;
&lt;p&gt;พอเราทำ config เสร็จเรียบร้อยแล้ว ก็เหมือนกับบ้านที่พร้อมจะขนเฟอร์นิเจอร์ (service จริง) เข้ามาวางแล้วครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3-1-architecture-overview-cloudflare-nginx-actual-budget&quot;&gt;3.1 Architecture Overview: Cloudflare + Nginx + Actual Budget&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-1-architecture-overview-cloudflare-nginx-actual-budget&quot; aria-label=&quot;Anchor link for: 3-1-architecture-overview-cloudflare-nginx-actual-budget&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ก่อนที่เราจะไปขอ Certificate จาก Cloudflare ผมอยากชวนมาดู &lt;strong&gt;ภาพรวมการทำงาน&lt;&#x2F;strong&gt; ของระบบนี้กันก่อนครับ จะได้เข้าใจว่า Nginx มีหน้าที่อะไร ทำไมต้องอยู่ตรงกลางระหว่าง Cloudflare กับ Actual Budget&lt;&#x2F;p&gt;
&lt;p&gt;ลองนึกภาพเป็นอาคารสำนักงานหนึ่งหลังที่มี &lt;strong&gt;รปภ.&lt;&#x2F;strong&gt; (Cloudflare) ยืนอยู่หน้าประตูใหญ่ ใครจะเข้ามาในตึกก็ต้องผ่านรปภ.ก่อน ตรวจบัตร ตรวจความปลอดภัย แล้วถ้าไม่มีปัญหา ถึงจะปล่อยให้เข้าไปในตัวตึก&lt;&#x2F;p&gt;
&lt;p&gt;ในโลกของเราก็คล้าย ๆ กันครับ&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;User&lt;&#x2F;strong&gt; → คือคนที่เดินเข้ามาในตึก ก็คือผู้ใช้ที่เปิดเว็บ &lt;code&gt;https:&#x2F;&#x2F;actual-budget.mydomain.com&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Cloudflare Proxy&lt;&#x2F;strong&gt; → คือรปภ. ด่านแรก คอยตรวจสอบ request ว่ามาจาก bot หรือเปล่า, มี DDoS หรือเปล่า, และช่วย terminate TLS แรกให้&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Nginx (บน VM)&lt;&#x2F;strong&gt; → คือพนักงานต้อนรับในอาคาร ที่คอยรับ request ต่อจาก Cloudflare แล้วกระจายงานไปยังห้องต่าง ๆ ในตึก (service ภายใน VM)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Actual Budget Container&lt;&#x2F;strong&gt; → ก็คือห้องทำงานจริง ๆ ข้างในตึก ที่คอยประมวลผลและตอบกลับ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ดังนั้น flow ของการสื่อสารจะเป็นแบบนี้ครับ:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ep2-setup-actual-budget-vm-docker-nginx-cloudflare&#x2F;architecture.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ผู้ใช้เชื่อมต่อแบบ HTTPS ปลอดภัยมาถึง Cloudflare&lt;&#x2F;li&gt;
&lt;li&gt;Cloudflare เปิด connection ใหม่ไปหา VM ผ่าน HTTPS อีกรอบ โดยเช็ก certificate ของ Nginx (ซึ่งเราจะใช้ Origin CA ที่ Cloudflare ออกให้)&lt;&#x2F;li&gt;
&lt;li&gt;Nginx ทำหน้าที่เป็น reverse proxy → รับ request แล้วส่งต่อไปยัง container ของ Actual Budget ที่รันอยู่ใน Docker&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Key Point:&lt;&#x2F;strong&gt;
Nginx ไม่ได้ทำงานแทน Cloudflare แต่ทำหน้าที่เป็น &lt;strong&gt;“ฝั่งรับ”&lt;&#x2F;strong&gt; ของ certificate ที่ Cloudflare ไว้ใจ และช่วย forward traffic ไปยังแอปของเราอย่างถูกต้อง&lt;&#x2F;p&gt;
&lt;p&gt;แบบนี้เวลาเราไปขอ Cloudflare Origin Certificate ผู้อ่านจะเข้าใจทันทีว่ามันไม่ใช่การขอ cert มาแปะมั่ว ๆ แต่คือการ “ทำกุญแจบ้าน” ที่ Cloudflare และ Nginx จะใช้ในการเชื่อมต่อกันครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;4-kh-cloudflare-origin-certificate&quot;&gt;4. ขอ Cloudflare Origin Certificate&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-kh-cloudflare-origin-certificate&quot; aria-label=&quot;Anchor link for: 4-kh-cloudflare-origin-certificate&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;โอเคครับ พอเราเข้าใจ Architecture แล้วว่า Cloudflare → Nginx → Actual Budget มันเชื่อมกันยังไง สิ่งสำคัญถัดมาก็คือ &lt;strong&gt;“ทำให้ Cloudflare เชื่อมั่นใน Nginx ของเรา”&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;โดยปกติแล้ว ถ้าเราอยากให้เซิร์ฟเวอร์มี HTTPS เรามีสองทางเลือก:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ใช้ Certificate ทั่วไปจาก CA&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;อาจจะเป็นฟรีอย่าง &lt;strong&gt;Let’s Encrypt&lt;&#x2F;strong&gt; หรือแบบเสียตังค์จากผู้ให้บริการอย่าง DigiCert, Sectigo ฯลฯ&lt;&#x2F;li&gt;
&lt;li&gt;จุดเด่นคือ cert แบบนี้ &lt;strong&gt;browser ทั่วไปก็เชื่อถือได้&lt;&#x2F;strong&gt; เวลาผู้ใช้เข้าเว็บตรงมาที่ origin (ไม่ผ่าน Cloudflare) ก็จะไม่เจอ warning ใด ๆ&lt;&#x2F;li&gt;
&lt;li&gt;ข้อเสียคือ Let’s Encrypt อายุสั้น (90 วัน) ต้องต่ออายุเรื่อย ๆ ส่วน cert ที่เสียเงินก็แพงกว่า&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ใช้ Cloudflare Origin Certificate&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare ออกให้โดยตรงเพื่อใช้ระหว่าง &lt;strong&gt;Cloudflare ↔ Origin Server (Nginx&#x2F;VM)&lt;&#x2F;strong&gt; เท่านั้น&lt;&#x2F;li&gt;
&lt;li&gt;อายุยาวมาก (default 15 ปี) หมายความว่าเราไม่ต้องปวดหัวคอย renew บ่อย ๆ&lt;&#x2F;li&gt;
&lt;li&gt;แต่ cert แบบนี้ &lt;strong&gt;browser ปกติจะไม่เชื่อ&lt;&#x2F;strong&gt; ถ้าเข้าเว็บตรงไปที่ origin IP (จะขึ้น warning) → เพราะมันออกมาเพื่อให้ Cloudflare ใช้ validate กับ origin โดยเฉพาะ&lt;&#x2F;li&gt;
&lt;li&gt;ซึ่งก็โอเคอยู่แล้ว เพราะผู้ใช้จริงจะต้องเข้าผ่าน Cloudflare Proxy เสมอ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;พูดง่าย ๆ เลยก็คือ:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ถ้าอยากให้ &lt;strong&gt;คนกับ browser เชื่อ&lt;&#x2F;strong&gt; → ใช้ Let’s Encrypt &#x2F; CA ปกติ&lt;&#x2F;li&gt;
&lt;li&gt;ถ้าอยากให้ &lt;strong&gt;Cloudflare เชื่อ&lt;&#x2F;strong&gt; (สำหรับ Full Strict) → ใช้ &lt;strong&gt;Origin CA&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;และในโปรเจกต์ Actual Budget ของเรา เนื่องจากผู้ใช้ทุกคนจะวิ่งผ่าน Cloudflare อยู่แล้ว เราก็เลือกใช้ &lt;strong&gt;Origin Cert&lt;&#x2F;strong&gt; เพื่อความสบายใจและลดภาระการต่ออายุครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;khant-nkaarkh-origin-cert&quot;&gt;ขั้นตอนการขอ Origin Cert&lt;a class=&quot;zola-anchor&quot; href=&quot;#khant-nkaarkh-origin-cert&quot; aria-label=&quot;Anchor link for: khant-nkaarkh-origin-cert&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;เข้าไปที่ &lt;strong&gt;Cloudflare Dashboard → SSL&#x2F;TLS → Origin Server → Create Certificate&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เลือก hostname ของเรา เช่น &lt;code&gt;actual-budget.mydomain.com&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เลือก key type: RSA&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เลือก validity: default (15 ปี)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Cloudflare จะสร้างไฟล์มาให้สองอัน:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Origin Certificate&lt;&#x2F;strong&gt; → เก็บเป็น &lt;code&gt;origin.crt&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Private Key&lt;&#x2F;strong&gt; → เก็บเป็น &lt;code&gt;origin.key&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;จากนั้นเราก็จะเอาไฟล์สองตัวนี้ไปใส่ใน Nginx เพื่อให้ Cloudflare เชื่อมต่อเข้ามาแบบ Full Strict ได้อย่างปลอดภัยครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;5-tangkhaa-nginx-reverse-proxy&quot;&gt;5. ตั้งค่า Nginx (Reverse Proxy)&lt;a class=&quot;zola-anchor&quot; href=&quot;#5-tangkhaa-nginx-reverse-proxy&quot; aria-label=&quot;Anchor link for: 5-tangkhaa-nginx-reverse-proxy&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ตอนนี้เรามี VM (ที่ดิน), Docker (บ้านสำเร็จรูป), และ Origin Certificate (กุญแจที่ Cloudflare ออกให้) เรียบร้อยแล้ว สิ่งที่ขาดไม่ได้เลยก็คือ &lt;strong&gt;“พนักงานต้อนรับ”&lt;&#x2F;strong&gt; ที่คอยรับแขกทุกคนที่เดินเข้ามาในตึก → นั่นก็คือ &lt;strong&gt;Nginx&lt;&#x2F;strong&gt; ครับ&lt;&#x2F;p&gt;
&lt;p&gt;Nginx ทำหน้าที่เป็น &lt;strong&gt;Reverse Proxy&lt;&#x2F;strong&gt; ก็คือเวลามี request มาจาก Cloudflare → Nginx จะเป็นคนแรกที่รับ จากนั้นมันจะตรวจว่า request ไปไหน แล้วส่งต่อให้ service ข้างใน (Actual Budget container) อีกที&lt;&#x2F;p&gt;
&lt;p&gt;ลองนึกภาพง่าย ๆ:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare = รปภ. หน้าตึก&lt;&#x2F;li&gt;
&lt;li&gt;Nginx = เคาน์เตอร์พนักงานต้อนรับ&lt;&#x2F;li&gt;
&lt;li&gt;Actual Budget = ห้องทำงานจริง ๆ ที่อยู่ด้านใน&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;เวลาคน (User) เดินเข้ามา → Cloudflare ตรวจบัตรแล้วปล่อยผ่าน → พนักงานต้อนรับ (Nginx) จะเป็นคนบอกว่า “อ๋อ คุณจะไปห้อง Actual Budget ใช่ไหม? เชิญทางนี้เลย” แล้วส่ง request เข้าห้องถูกต้อง&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;config-nginx&quot;&gt;Config Nginx&lt;a class=&quot;zola-anchor&quot; href=&quot;#config-nginx&quot; aria-label=&quot;Anchor link for: config-nginx&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เราจะให้ Nginx ฟังทั้งพอร์ต 80 (HTTP) และ 443 (HTTPS)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;พอร์ต 80: แค่ redirect ทุก request ไปที่ HTTPS (เพื่อบังคับเข้ารหัสเสมอ)&lt;&#x2F;li&gt;
&lt;li&gt;พอร์ต 443: ฟังด้วย SSL (ใช้ Origin Cert ที่ Cloudflare ออกให้) แล้วทำ proxy pass ไปยัง Actual Budget container&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ตัวอย่าง config (แบบย่อ):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nginx&quot; class=&quot;language-nginx z-code&quot;&gt;&lt;code class=&quot;language-nginx&quot; data-lang=&quot;nginx&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;server {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  listen 80;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  server_name actual-budget.mydomain.com;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  return 301 https:&#x2F;&#x2F;$host$request_uri;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;server {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  listen 443 ssl http2;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  server_name actual-budget.mydomain.com;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  ssl_certificate     &#x2F;etc&#x2F;nginx&#x2F;certs&#x2F;actual-budget.mydomain.com&#x2F;origin.crt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  ssl_certificate_key &#x2F;etc&#x2F;nginx&#x2F;certs&#x2F;actual-budget.mydomain.com&#x2F;origin.key;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  ssl_protocols TLSv1.2 TLSv1.3;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  ssl_ciphers HIGH:!aNULL:!MD5;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  location &#x2F; {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    proxy_pass http:&#x2F;&#x2F;actual:5006;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    proxy_set_header Host $host;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    proxy_set_header X-Real-IP $remote_addr;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    proxy_set_header X-Forwarded-Proto https;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ในที่นี้ &lt;code&gt;proxy_pass http:&#x2F;&#x2F;actual:5006;&lt;&#x2F;code&gt; หมายถึง Nginx จะส่งต่อ traffic ไปยัง container ของ Actual Budget ที่รันบนพอร์ต 5006&lt;&#x2F;p&gt;
&lt;h3 id=&quot;key-point-thiit-ngekhaaaicch&quot;&gt;Key Point ที่ต้องเข้าใจ&lt;a class=&quot;zola-anchor&quot; href=&quot;#key-point-thiit-ngekhaaaicch&quot; aria-label=&quot;Anchor link for: key-point-thiit-ngekhaaaicch&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cloudflare → Nginx&lt;&#x2F;strong&gt; เชื่อมกันด้วย HTTPS (Origin Cert)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Nginx → Actual Budget Container&lt;&#x2F;strong&gt; ใช้ HTTP ธรรมดาภายใน VM ก็พอ เพราะมันวิ่งในเครือข่าย local อยู่แล้ว&lt;&#x2F;li&gt;
&lt;li&gt;User ไม่มีทางเข้ามาถึง Nginx โดยตรง ต้องวิ่งผ่าน Cloudflare เสมอ → ทำให้ปลอดภัย&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;พอ config Nginx เสร็จแล้วก็เหมือนเราได้ “พนักงานต้อนรับที่พร้อมเปิดตึก” ไว้เรียบร้อย รอเพียงแค่ยกของ (config และ cert) ขึ้นไปไว้บน VM แล้ว start ระบบจริง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;5-1-authenticated-origin-pulls-ephimrpph-s-ngchan&quot;&gt;5.1 Authenticated Origin Pulls (เพิ่มรปภ. สองชั้น)&lt;a class=&quot;zola-anchor&quot; href=&quot;#5-1-authenticated-origin-pulls-ephimrpph-s-ngchan&quot; aria-label=&quot;Anchor link for: 5-1-authenticated-origin-pulls-ephimrpph-s-ngchan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ถึงตรงนี้เราจะเห็นว่า Nginx ของเรามี &lt;strong&gt;Origin Certificate&lt;&#x2F;strong&gt; แล้ว Cloudflare ก็เชื่อมต่อมาด้วย HTTPS แบบ Full Strict ได้ แต่ในบางกรณี เรายังอาจกังวลอยู่ว่า… “แล้วถ้ามีใครสักคนพยายามข้าม Cloudflare แล้วยิง HTTPS ตรงเข้ามาที่ Nginx โดยตรงล่ะ?”&lt;&#x2F;p&gt;
&lt;p&gt;ปกติแล้วมันอาจจะยังต่อได้ (ถ้ารู้ IP VM ตรง ๆ) เพราะ Origin Cert ถูกออกมาให้ Cloudflare ใช้ แต่ browser ปกติไม่รู้จักก็จะขึ้น warning → อย่างไรก็ตาม ถ้าเป็น attacker ที่บังคับข้าม Cloudflare เข้ามา Nginx ก็อาจจะยังเปิดรับอยู่&lt;&#x2F;p&gt;
&lt;p&gt;ตรงนี้แหละครับที่ &lt;strong&gt;Authenticated Origin Pulls&lt;&#x2F;strong&gt; เข้ามาแก้ปัญหา&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mankhuue-aair&quot;&gt;มันคืออะไร?&lt;a class=&quot;zola-anchor&quot; href=&quot;#mankhuue-aair&quot; aria-label=&quot;Anchor link for: mankhuue-aair&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare จะส่ง &lt;strong&gt;client certificate&lt;&#x2F;strong&gt; ของตัวเองมาพร้อมกับการเชื่อมต่อ HTTPS ทุกครั้ง&lt;&#x2F;li&gt;
&lt;li&gt;Nginx (ฝั่ง origin) จะตรวจสอบ cert นั้นว่าเป็นของ Cloudflare จริงหรือเปล่า&lt;&#x2F;li&gt;
&lt;li&gt;ถ้าไม่ใช่ → ปฏิเสธ connection ทันที&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;พูดง่าย ๆ ก็คือ เพิ่มการตรวจว่า &lt;strong&gt;“คนที่เข้ามาเป็น Cloudflare จริง ๆ นะ ไม่ใช่ใครก็ได้ที่ต่อ HTTPS มาหาเรา”&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;nginx-config-esrim&quot;&gt;Nginx Config (เสริม)&lt;a class=&quot;zola-anchor&quot; href=&quot;#nginx-config-esrim&quot; aria-label=&quot;Anchor link for: nginx-config-esrim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;นอกจาก ssl_certificate &#x2F; ssl_certificate_key ของ Origin Cert แล้ว เราเพิ่ม config นี้เข้าไป:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nginx&quot; class=&quot;language-nginx z-code&quot;&gt;&lt;code class=&quot;language-nginx&quot; data-lang=&quot;nginx&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ssl_client_certificate &#x2F;etc&#x2F;nginx&#x2F;certs&#x2F;cloudflare&#x2F;origin-pull-ca.pem;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ssl_verify_client on;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;origin-pull-ca.pem&lt;&#x2F;code&gt; คือ certificate ของ Cloudflare ที่เราโหลดมาจากหน้า Origin Pulls ของ Cloudflare&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;ssl_verify_client on;&lt;&#x2F;code&gt; บังคับให้ Nginx ยอมคุยเฉพาะกับ client (Cloudflare) ที่ถือ cert ตัวนี้เท่านั้น&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;epriiybethiiybaihehnphaaph&quot;&gt;เปรียบเทียบให้เห็นภาพ&lt;a class=&quot;zola-anchor&quot; href=&quot;#epriiybethiiybaihehnphaaph&quot; aria-label=&quot;Anchor link for: epriiybethiiybaihehnphaaph&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;เดิมทีมีแค่ &lt;strong&gt;กุญแจล็อกประตู (Origin Cert)&lt;&#x2F;strong&gt; → Cloudflare มีกุญแจไขเข้ามาได้&lt;&#x2F;li&gt;
&lt;li&gt;แต่ตอนนี้เพิ่ม &lt;strong&gt;ตรวจบัตรพนักงาน (Authenticated Pull Cert)&lt;&#x2F;strong&gt; → ต่อให้ใครลอกกุญแจเลียนแบบมา แต่ถ้าไม่มีบัตรที่ Cloudflare ออกจริง ก็เข้าไม่ได้&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;สรุปคือ ถ้าเราเปิด &lt;strong&gt;Authenticated Origin Pulls&lt;&#x2F;strong&gt; เราจะมั่นใจได้เลยว่า &lt;strong&gt;ทุก request ที่ถึง Nginx ต้องมาจาก Cloudflare เท่านั้น&lt;&#x2F;strong&gt; ไม่ใช่ attacker ที่พยายามเข้าตรง ๆ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;6-deploy-configuration-aipthii-vm&quot;&gt;6. Deploy Configuration ไปที่ VM&lt;a class=&quot;zola-anchor&quot; href=&quot;#6-deploy-configuration-aipthii-vm&quot; aria-label=&quot;Anchor link for: 6-deploy-configuration-aipthii-vm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;โอเคครับ ตอนนี้เรามีทุกอย่างครบแล้ว ทั้ง &lt;strong&gt;Docker&#x2F;Compose&lt;&#x2F;strong&gt; (บ้านสำเร็จรูป), &lt;strong&gt;Nginx config&lt;&#x2F;strong&gt; (พนักงานต้อนรับ), และ &lt;strong&gt;Origin Certificate&lt;&#x2F;strong&gt; (กุญแจบ้าน) รวมถึงถ้าอยากปลอดภัยสุด ๆ ก็มี &lt;strong&gt;Authenticated Origin Pulls&lt;&#x2F;strong&gt; (ตรวจบัตรพนักงาน) …ทีนี้ก็ถึงเวลาขนของจริงไปลงบน VM ของเราแล้ว&lt;&#x2F;p&gt;
&lt;p&gt;การ deploy ตรงนี้ก็เปรียบเหมือนกับการ &lt;strong&gt;ย้ายเฟอร์นิเจอร์และของใช้ทั้งหมดเข้าบ้านใหม่&lt;&#x2F;strong&gt; นั่นแหละครับ เราจะเอาไฟล์สำคัญ ๆ เช่น:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.env&lt;&#x2F;code&gt; (ค่าตั้งต่าง ๆ ของ Actual Budget)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt; (แปลนบ้าน)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;nginx&#x2F;conf.d&#x2F;&lt;&#x2F;code&gt; (พนักงานต้อนรับ)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;origin.crt&lt;&#x2F;code&gt; + &lt;code&gt;origin.key&lt;&#x2F;code&gt; (กุญแจบ้าน)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;แพ็กทั้งหมดขึ้นรถบรรทุก (deployment script) แล้วส่งไปยัง VM ผ่าน SSH&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;flow-kh-ngkaar-deploy&quot;&gt;Flow ของการ Deploy&lt;a class=&quot;zola-anchor&quot; href=&quot;#flow-kh-ngkaar-deploy&quot; aria-label=&quot;Anchor link for: flow-kh-ngkaar-deploy&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ตรวจสอบไฟล์ config ฝั่งเราให้เรียบร้อยก่อน&lt;&#x2F;strong&gt; → เหมือนตรวจเช็กว่าของครบมั้ยก่อนย้ายบ้าน&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ใช้ script ส่งไฟล์ขึ้น VM ผ่าน SCP&#x2F;rsync&lt;&#x2F;strong&gt; → เหมือนขนเฟอร์นิเจอร์ขึ้นรถแล้วไปส่ง&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;เซ็ต permission บน cert&lt;&#x2F;strong&gt; → เพื่อให้กุญแจบ้าน (origin.key) ถูกเก็บอย่างปลอดภัย มีแค่ Nginx อ่านได้&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;วางไฟล์ทั้งหมดลงที่ directory ของ VM&lt;&#x2F;strong&gt; เช่น &lt;code&gt;&#x2F;home&#x2F;ubuntu&#x2F;actual&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;SSH เข้า VM เพื่อตรวจสอบอีกที&lt;&#x2F;strong&gt; ว่าของมาถึงครบ พร้อมใช้งาน&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;taw-yaangkhamsang-deploy&quot;&gt;ตัวอย่างคำสั่ง Deploy&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangkhamsang-deploy&quot; aria-label=&quot;Anchor link for: taw-yaangkhamsang-deploy&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;REMOTE_HOST&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;203.0.113.10&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;REMOTE_USER&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;ubuntu&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;REMOTE_DIR&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&#x2F;home&#x2F;ubuntu&#x2F;actual&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;SSH_KEY&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;id_ed25519&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;.&#x2F;deploy-config.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;script นี้จะช่วยเรา validate ไฟล์, copy ขึ้น VM, เซ็ตสิทธิ์ไฟล์ cert ให้เรียบร้อย แล้วสรุปขั้นตอนต่อไปให้&lt;&#x2F;p&gt;
&lt;p&gt;พอเสร็จขั้นตอนนี้ เราจะได้ “บ้านพร้อมอยู่” แล้วครับ เหลือแค่สั่งเปิดไฟ (start service) ทุกอย่างก็พร้อมทำงานจริง 🎉&lt;&#x2F;p&gt;
&lt;h2 id=&quot;7-tangkhaa-dns-bn-cloudflare&quot;&gt;7. ตั้งค่า DNS บน Cloudflare&lt;a class=&quot;zola-anchor&quot; href=&quot;#7-tangkhaa-dns-bn-cloudflare&quot; aria-label=&quot;Anchor link for: 7-tangkhaa-dns-bn-cloudflare&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;โอเคครับ ถึงตอนนี้บ้านของเราก็พร้อมแล้ว ทั้งโครงสร้างภายใน (Docker + Actual Budget), พนักงานต้อนรับ (Nginx), และกุญแจบ้าน (Origin Cert) …แต่ปัญหาคือคนทั่วไป &lt;strong&gt;ยังไม่รู้ว่าบ้านเราอยู่ที่ไหน&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ตรงนี้เองที่ &lt;strong&gt;DNS&lt;&#x2F;strong&gt; เข้ามามีบทบาทครับ มันก็เหมือน &lt;strong&gt;สมุดหน้าเหลือง &#x2F; Google Maps&lt;&#x2F;strong&gt; ที่บอกว่า “ถ้าอยากไปบ้านนี้ ให้ตามพิกัดนี้ไปนะ”&lt;&#x2F;p&gt;
&lt;p&gt;ใน Cloudflare เราจะต้องเข้าไปเพิ่ม DNS record ให้ domain&#x2F;subdomain ของเรา เช่น:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;actual-budget.mydomain.com&lt;&#x2F;code&gt; → ชี้ไปที่ &lt;strong&gt;IP ของ VM&lt;&#x2F;strong&gt; ของเรา&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;khant-nain-cloudflare&quot;&gt;ขั้นตอนใน Cloudflare&lt;a class=&quot;zola-anchor&quot; href=&quot;#khant-nain-cloudflare&quot; aria-label=&quot;Anchor link for: khant-nain-cloudflare&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;เข้า &lt;strong&gt;Cloudflare Dashboard → DNS&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เพิ่ม A record:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;actual-budget&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Value: &lt;code&gt;&amp;lt;VM_PUBLIC_IP&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Proxy: เปิดเป็น &lt;strong&gt;Proxied (เมฆสีส้ม)&lt;&#x2F;strong&gt; ☁️&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ไปที่ &lt;strong&gt;SSL&#x2F;TLS → Overview&lt;&#x2F;strong&gt; แล้วเลือก &lt;strong&gt;Full (Strict)&lt;&#x2F;strong&gt; เพื่อให้ Cloudflare บังคับเชื่อมกับ Origin เฉพาะที่มี cert ถูกต้องเท่านั้น&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;(Optional) เปิด &lt;strong&gt;Authenticated Origin Pulls&lt;&#x2F;strong&gt; ถ้าเรา config ไว้ที่ Nginx แล้ว&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;phaaphrwm-flow-hlangtangkhaa-dns&quot;&gt;ภาพรวม Flow หลังตั้งค่า DNS&lt;a class=&quot;zola-anchor&quot; href=&quot;#phaaphrwm-flow-hlangtangkhaa-dns&quot; aria-label=&quot;Anchor link for: phaaphrwm-flow-hlangtangkhaa-dns&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[ User ] → actual-budget.mydomain.com
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;   ↓ (DNS lookup by Cloudflare)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[ Cloudflare Proxy ] --HTTPS (Origin Cert)--&amp;gt; [ Nginx @ VM ] → [ Actual Budget ]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;พอถึงตรงนี้ ทุกอย่างเริ่มเข้าที่เข้าทางแล้วครับ ผู้ใช้ก็สามารถพิมพ์ &lt;code&gt;https:&#x2F;&#x2F;actual-budget.mydomain.com&lt;&#x2F;code&gt; แล้วระบบจะวิ่งผ่าน Cloudflare → Nginx → Container ได้อย่างปลอดภัย 🔒&lt;&#x2F;p&gt;
&lt;h2 id=&quot;8-start-service-test&quot;&gt;8. Start Service + Test&lt;a class=&quot;zola-anchor&quot; href=&quot;#8-start-service-test&quot; aria-label=&quot;Anchor link for: 8-start-service-test&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;โอเคครับ ตอนนี้ทุกอย่างเราขนเข้าบ้านเรียบร้อยแล้ว ไม่ว่าจะเป็นโครงสร้าง (Docker), พนักงานต้อนรับ (Nginx), กุญแจบ้าน (Origin Cert), และบอกพิกัดบ้านบนแผนที่ (DNS) …ทีนี้ก็ถึงเวลาสำคัญที่สุด คือ &lt;strong&gt;เปิดไฟบ้านให้ใช้งานจริง&lt;&#x2F;strong&gt; ครับ 💡&lt;&#x2F;p&gt;
&lt;p&gt;บน VM ของเรา เราเพียงเข้าไปที่ directory ที่เก็บไฟล์ทั้งหมด (เช่น &lt;code&gt;&#x2F;home&#x2F;ubuntu&#x2F;actual&lt;&#x2F;code&gt;) แล้วสั่ง:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; compose up&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้น Docker ก็จะยกทุก container ขึ้นมาพร้อมกัน ทั้ง Actual Budget, Nginx, และ service ที่เกี่ยวข้อง&lt;&#x2F;p&gt;
&lt;h3 id=&quot;trwcchs-bwaarabbthamngaancchring&quot;&gt;ตรวจสอบว่าระบบทำงานจริง&lt;a class=&quot;zola-anchor&quot; href=&quot;#trwcchs-bwaarabbthamngaancchring&quot; aria-label=&quot;Anchor link for: trwcchs-bwaarabbthamngaancchring&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;ใช้ &lt;code&gt;docker ps&lt;&#x2F;code&gt; → เหมือนเดินดูว่าทุกห้องในบ้านมีไฟติดครบ&lt;&#x2F;li&gt;
&lt;li&gt;ใช้ &lt;code&gt;docker logs -f nginx&lt;&#x2F;code&gt; → ดูว่าพนักงานต้อนรับ (Nginx) ตอบสนองปกติไหม&lt;&#x2F;li&gt;
&lt;li&gt;ใช้ &lt;code&gt;curl -I https:&#x2F;&#x2F;actual-budget.mydomain.com&lt;&#x2F;code&gt; → ทดลอง “กดกริ่งบ้าน” จากข้างนอก&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ถ้าได้ status &lt;code&gt;200 OK&lt;&#x2F;code&gt; ก็แปลว่าบ้านเราเปิดรับแขกแล้วครับ 🎉&lt;&#x2F;p&gt;
&lt;h3 id=&quot;epidebraawech-r&quot;&gt;เปิดเบราว์เซอร์&lt;a class=&quot;zola-anchor&quot; href=&quot;#epidebraawech-r&quot; aria-label=&quot;Anchor link for: epidebraawech-r&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;พิมพ์ใน browser:&lt;&#x2F;p&gt;
&lt;p&gt;👉 &lt;code&gt;https:&#x2F;&#x2F;actual-budget.mydomain.com&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าทุกอย่างเรียบร้อย คุณจะเจอหน้าเว็บ Actual Budget พร้อมกุญแจเขียว 🔒 โผล่ขึ้นมา → แปลว่า TLS ทำงานครบทั้งเส้นทาง (User → Cloudflare → Nginx → Container) แล้ว&lt;&#x2F;p&gt;
&lt;p&gt;พูดง่าย ๆ เลยก็คือ จาก &lt;strong&gt;VM เปล่า ๆ&lt;&#x2F;strong&gt; เราก็เปลี่ยนมันเป็น &lt;strong&gt;เว็บแอปที่พร้อมใช้งานจริง&lt;&#x2F;strong&gt; ได้สำเร็จแล้วครับ 🚀&lt;&#x2F;p&gt;
&lt;h2 id=&quot;9-backup-strategy&quot;&gt;9. Backup Strategy&lt;a class=&quot;zola-anchor&quot; href=&quot;#9-backup-strategy&quot; aria-label=&quot;Anchor link for: 9-backup-strategy&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;พอเรามีบ้านใหม่เสร็จสรรพ เปิดไฟใช้งานจริงได้แล้ว สิ่งหนึ่งที่มักจะถูกลืม แต่สำคัญไม่แพ้กันก็คือ… &lt;strong&gt;การทำกุญแจสำรองและประกันบ้าน&lt;&#x2F;strong&gt;
ในโลกของระบบ นั่นก็คือ &lt;strong&gt;การทำ Backup&lt;&#x2F;strong&gt; ครับ&lt;&#x2F;p&gt;
&lt;p&gt;ลองนึกภาพดูว่า วันหนึ่งถ้าไฟดับ ฮาร์ดดิสก์พัง หรือเราเผลอลบไฟล์ผิดไป …เราจะอยากมีวิธี “ย้อนเวลา” กลับไปยังสภาพที่ระบบเคยใช้งานได้ปกติใช่ไหมครับ การทำ backup จึงเป็นเหมือนการเตรียม &lt;strong&gt;ประตูหนีไฟ&lt;&#x2F;strong&gt; เอาไว้ให้เราอุ่นใจ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;singthiikhwr-backup&quot;&gt;สิ่งที่ควร Backup&lt;a class=&quot;zola-anchor&quot; href=&quot;#singthiikhwr-backup&quot; aria-label=&quot;Anchor link for: singthiikhwr-backup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ข้อมูลผู้ใช้ + งบการเงิน&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;เก็บอยู่ใน directory &lt;code&gt;.&#x2F;actual-data&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ตรงนี้คือหัวใจของ Actual Budget เลย เพราะมันบันทึกข้อมูลทั้งหมดที่ผู้ใช้กรอก&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SSL Certificates (origin.crt + origin.key)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;แม้ว่าจะขอใหม่จาก Cloudflare ได้ แต่การเก็บสำรองไว้จะช่วยให้เรา restore ได้เร็วขึ้น&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ไฟล์ Config สำคัญ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.env&lt;&#x2F;code&gt;, &lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt;, &lt;code&gt;nginx&#x2F;conf.d&#x2F;*&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;เป็นเหมือนคู่มือบ้าน ถ้าไฟล์พวกนี้หาย ระบบอาจจะยังสร้างบ้านใหม่ได้ แต่จะต้องใช้เวลา setup นานขึ้น&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;aenwthaangkaar-backup&quot;&gt;แนวทางการ Backup&lt;a class=&quot;zola-anchor&quot; href=&quot;#aenwthaangkaar-backup&quot; aria-label=&quot;Anchor link for: aenwthaangkaar-backup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;ตั้ง cron job บน VM → copy &lt;code&gt;.&#x2F;actual-data&lt;&#x2F;code&gt; ออกไปยัง storage ภายนอก&lt;&#x2F;li&gt;
&lt;li&gt;หรือใช้ tool พวก rsync &#x2F; restic เพื่อ sync ข้อมูลเป็นระยะ ๆ&lt;&#x2F;li&gt;
&lt;li&gt;เก็บไฟล์สำรองไว้ใน cloud storage อื่น เช่น Azure Blob, S3, หรือแม้แต่ Google Drive ก็ได้&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;พูดง่าย ๆ ก็คือ Backup = &lt;strong&gt;กุญแจสำรอง&lt;&#x2F;strong&gt; + &lt;strong&gt;ประกันบ้าน&lt;&#x2F;strong&gt;
ทำให้มั่นใจว่า ต่อให้เกิดอะไรขึ้นกับ VM หรือ container …ข้อมูลการเงินของเราก็ยังไม่หายไปไหน&lt;&#x2F;p&gt;
&lt;h2 id=&quot;10-conclusion&quot;&gt;10. Conclusion&lt;a class=&quot;zola-anchor&quot; href=&quot;#10-conclusion&quot; aria-label=&quot;Anchor link for: 10-conclusion&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จากตอนแรกที่เราเริ่มต้นด้วย &lt;strong&gt;VM เปล่า ๆ&lt;&#x2F;strong&gt; เหมือนซื้อที่ดินโล่ง ๆ มาหนึ่งแปลง จนถึงตอนนี้เราสามารถสร้างบ้านที่พร้อมอยู่จริงได้สำเร็จแล้ว 🎉&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;เราเลือกใช้ &lt;strong&gt;VM&lt;&#x2F;strong&gt; เพราะ Actual Budget ใช้ SQLite เป็นฐานข้อมูลที่ต้องการ native filesystem → Managed Service อย่าง Azure App Service ไม่ตอบโจทย์&lt;&#x2F;li&gt;
&lt;li&gt;เราติดตั้ง &lt;strong&gt;Docker &amp;amp; Docker Compose&lt;&#x2F;strong&gt; เหมือนยกบ้านสำเร็จรูปมาลง → ทำให้จัดการ service ได้ง่ายและยืดหยุ่น&lt;&#x2F;li&gt;
&lt;li&gt;เรา config &lt;strong&gt;Environment และ Nginx&lt;&#x2F;strong&gt; → ทำหน้าที่เป็นพนักงานต้อนรับ คอยจัดการ traffic ที่วิ่งเข้ามา&lt;&#x2F;li&gt;
&lt;li&gt;เราขอ &lt;strong&gt;Cloudflare Origin Certificate&lt;&#x2F;strong&gt; → เป็นกุญแจสำคัญที่ทำให้ Cloudflare ยอมเชื่อมต่อกับ origin ได้แบบ Full (Strict)&lt;&#x2F;li&gt;
&lt;li&gt;เราเปิด &lt;strong&gt;Authenticated Origin Pulls&lt;&#x2F;strong&gt; → เป็นเหมือนการตรวจบัตรพนักงานที่มั่นใจได้ว่า request ที่เข้ามาต้องผ่าน Cloudflare จริง ๆ&lt;&#x2F;li&gt;
&lt;li&gt;เราตั้งค่า &lt;strong&gt;DNS บน Cloudflare&lt;&#x2F;strong&gt; → เพื่อบอกโลกว่าเว็บเราอยู่ตรงไหน&lt;&#x2F;li&gt;
&lt;li&gt;สุดท้าย เรา start service ขึ้นมา และปิดท้ายด้วยการทำ &lt;strong&gt;Backup Strategy&lt;&#x2F;strong&gt; ให้ชีวิตปลอดภัยขึ้นอีกขั้น&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ทั้งหมดนี้ก็คือการเอาทฤษฎีจาก &lt;strong&gt;EP1&lt;&#x2F;strong&gt; ที่เราคุยกันเรื่อง TLS Flow และ Certificate มา &lt;strong&gt;ลงมือจริงใน EP2&lt;&#x2F;strong&gt; จนกลายเป็นเว็บแอปที่เปิดใช้งานได้จริงพร้อม HTTPS&lt;&#x2F;p&gt;
&lt;p&gt;สำหรับผมแล้ว มันทำให้รู้สึกว่าเรื่อง SSL&#x2F;TLS ที่แต่ก่อนเคยดูเป็น “หลุมดำ” เต็มไปด้วยศัพท์เทคนิคยาก ๆ …พอเราแยกเป็นสถานการณ์, วาด flow ให้ง่าย, แล้วลองลงมือทำจริง มันก็ไม่ได้ยากเกินไปเลยครับ ✨&lt;&#x2F;p&gt;
&lt;p&gt;และนี่ก็คือ &lt;strong&gt;Actual Budget + Nginx + Cloudflare Origin Cert&lt;&#x2F;strong&gt; ที่ผมอยากเล่าให้ฟังในตอนนี้&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>เข้าใจ SSL&#x2F;TLS แบบง่าย ๆ ผ่าน Cloudflare และ Azure</title>
		<published>2025-08-23T00:00:00+00:00</published>
		<updated>2025-08-23T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/ssl-tls-made-easy-cloudflare-azure/" type="text/html"/>
		<id>https://thadaw.com/posts/ssl-tls-made-easy-cloudflare-azure/</id>
		<content type="html">&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;Series SSL&amp;#x2F;TLS กับ Cloudflare&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;ul&gt;
&lt;li&gt;EP 1: เข้าใจ SSL&#x2F;TLS แบบง่าย ๆ ผ่าน Cloudflare และ Azure (บทความนี้)&lt;&#x2F;li&gt;
&lt;li&gt;EP 2: &lt;a href=&quot;&#x2F;posts&#x2F;ep2-setup-actual-budget-vm-docker-nginx-cloudflare&#x2F;&quot;&gt;ลงมือจริง: Setup Actual Budget บน VM ด้วย Docker, Nginx และ Cloudflare&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;สวัสดีครับ วันนี้อยากมาเล่าเรื่อง &lt;strong&gt;SSL&#x2F;TLS หรือ HTTPS&lt;&#x2F;strong&gt; กันสักหน่อย
คือหลาย ๆ คน (รวมถึงตัวผมเองเมื่อก่อน) มักจะรู้สึกว่า SSL นี่มันเหมือน &lt;strong&gt;หลุมดำ&lt;&#x2F;strong&gt; เลยครับ
ไม่รู้ว่ามันทำงานยังไง เห็นแค่พอเปิดเว็บแล้วมี “กุญแจสีเขียว” โผล่มาในเบราว์เซอร์ ก็น่าจะโอเคแล้ว&lt;&#x2F;p&gt;
&lt;p&gt;แต่พอถึงเวลาที่ต้อง &lt;strong&gt;setup จริง หรือ maintain จริงๆ&lt;&#x2F;strong&gt; … มันกลับไม่ง่ายเลย
โดยเฉพาะการทำงานกับ &lt;strong&gt;certificate&lt;&#x2F;strong&gt; ที่ต้องต่ออายุ ต้องจัดการ key ต้องเข้าใจการ trust chain
พอไม่เข้าใจก็กลายเป็นปัญหาที่มึนได้ง่าย ๆ&lt;&#x2F;p&gt;
&lt;p&gt;เลยอยากเขียนบทความนี้มาเป็น &lt;strong&gt;สรุปแนวทางแบบเข้าใจง่าย ๆ&lt;&#x2F;strong&gt;
ใช้ &lt;strong&gt;ตัวอย่างจริง&lt;&#x2F;strong&gt; ทั้ง Cloudflare และ Azure ที่หลายคนน่าจะคุ้นเคย
และที่สำคัญ… จะมี &lt;strong&gt;diagram&lt;&#x2F;strong&gt; ให้เห็นภาพการทำงานด้วยครับ&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;สำหรับคนที่ใหม่กับ Azure&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;p&gt;จริงๆ Azure ทั้ง 2 Service ที่ผมพูดถึงในบทความนี้ App Service และ Container App ค่อยข้างเข้าใจง่ายนะครับ โดยทั้งคู่เป็น PAAS (Platform as a Service) ที่เราไม่ต้องไปจัดการ VM เองเลย แค่ deploy code ขึ้นไป แล้ว Azure จะจัดการทุกอย่างให้เอง&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าใครสนใจผมเคยพูดเกี่ยวกับ Azure App Service ไว้ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=obtIYPkwm90&quot;&gt;YouTube: Deploy Web App อย่างง่ายด้วย Azure App Service | Azure Note Series&lt;&#x2F;a&gt; ครับ&lt;&#x2F;p&gt;
&lt;p&gt;และเคยพูดเรื่องของ Azure Container App ไว้ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;RVb0gXZ6H2so&quot;&gt;YouTube: Serverless container on Microsoft Azure | Azure Developer Day 2023&lt;&#x2F;a&gt; ครับ&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่ง Azure App Service จะมี Free Tier ให้ลองเล่นฟรี ๆ ได้เลย ส่วน Azure Container App สามารถ Scale to zero ได้ ทำให้ถ้าเราใช้ในโปรเจกต์เล็ก ๆ ก็จะประหยัดค่าใช้จ่ายได้มากครับ หรือ ไม่ค่อยมีคนใช้งาน ก็แทบไม่เสียค่าใช้จ่ายอะไรเลย&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;&lt;h2 id=&quot;ssl-tls-khuue-aair&quot;&gt;SSL&#x2F;TLS คืออะไร&lt;a class=&quot;zola-anchor&quot; href=&quot;#ssl-tls-khuue-aair&quot; aria-label=&quot;Anchor link for: ssl-tls-khuue-aair&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เวลาเราเข้าเว็บที่ขึ้นว่า &lt;code&gt;https:&#x2F;&#x2F;&lt;&#x2F;code&gt; หลายคนอาจจะรู้สึกว่า “อ๋อ ก็คือเว็บปลอดภัย” มีรูปกุญแจเล็ก ๆ โผล่มาตรง address bar แค่นั้น แต่จริง ๆ แล้วเบื้องหลังของเจ้าตัว HTTPS มันก็คือสิ่งที่เรียกว่า &lt;strong&gt;SSL&#x2F;TLS&lt;&#x2F;strong&gt; นี่แหละครับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;http-https-cert.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ลองนึกภาพว่าเรากำลังส่งจดหมายหากัน ถ้าเป็น HTTP ปกติ มันก็เหมือนเราเขียนจดหมายใส่กระดาษแล้วส่งไปตรง ๆ ใครดักกลางทางก็เปิดอ่านได้หมด แต่ถ้าเป็น HTTPS มันเหมือนเรายัดจดหมายนั้นใส่กล่องเหล็กที่มีกุญแจล็อกไว้ แล้วมอบกุญแจให้เฉพาะผู้รับเท่านั้นที่จะเปิดออกมาอ่านได้&lt;&#x2F;p&gt;
&lt;p&gt;SSL (Secure Sockets Layer) และ TLS (Transport Layer Security) ก็คือ “กล่องเหล็กพร้อมกุญแจ” นี่เองครับ มันเป็นโปรโตคอลที่ทำหน้าที่เข้ารหัสข้อมูลระหว่าง &lt;strong&gt;ผู้ใช้&lt;&#x2F;strong&gt; กับ &lt;strong&gt;เซิร์ฟเวอร์&lt;&#x2F;strong&gt; ทำให้คนอื่น ๆ ที่พยายามดักดูระหว่างทาง ไม่สามารถอ่านหรือแก้ไขข้อมูลได้ง่าย ๆ&lt;&#x2F;p&gt;
&lt;p&gt;แต่ไม่ใช่แค่เรื่องการเข้ารหัสเท่านั้นนะครับ อีกหน้าที่หนึ่งที่สำคัญมากของ SSL&#x2F;TLS ก็คือ &lt;strong&gt;การยืนยันตัวตน (Authentication)&lt;&#x2F;strong&gt; ว่าเซิร์ฟเวอร์ที่เรากำลังคุยด้วยนั้นเป็น “ของจริง” ไม่ใช่เว็บปลอมที่ใครบางคนตั้งขึ้นมาเพื่อหลอกเรา ซึ่งหน้าที่ตรงนี้แหละที่ certificate เข้ามามีบทบาท เปรียบเหมือน “บัตรประชาชน” ของเว็บไซต์ที่ออกโดยหน่วยงานที่เชื่อถือได้ (CA – Certificate Authority)&lt;&#x2F;p&gt;
&lt;p&gt;ดังนั้นเวลาที่เราบอกว่า “เปิดเว็บนี้แบบ HTTPS” จริง ๆ มันหมายความว่า เรากำลังเชื่อมต่อผ่าน TLS โดยมี certificate ที่คอยการันตีความน่าเชื่อถือ และ การเข้ารหัสข้อมูลครบถ้วน&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sthaankaarnthiiecch-b-ykab-ssl-tls&quot;&gt;สถานการณ์ที่เจอบ่อยกับ SSL&#x2F;TLS&lt;a class=&quot;zola-anchor&quot; href=&quot;#sthaankaarnthiiecch-b-ykab-ssl-tls&quot; aria-label=&quot;Anchor link for: sthaankaarnthiiecch-b-ykab-ssl-tls&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;วันนี้ผมมี 2 สถานการณ์มาเล่าให้ฟังครับ ว่าในแต่ละสถานการณ์ เราจะจัดการกับ SSL&#x2F;TLS ยังไงให้เหมาะสม&lt;&#x2F;p&gt;
&lt;p&gt;โดยจริงๆ แล้วเราไม่จำเป็นต้องใช้ Cloudflare หรือ Azure ก็ได้นะครับ แต่ผมจะใช้ Cloudflare เป็นตัวอย่างของทั้ง DNS และ Proxy ที่หลายคนน่าจะคุ้นเคยกันดี ส่วน Azure ก็จะใช้เป็นตัวอย่างของ &lt;strong&gt;Managed Service&lt;&#x2F;strong&gt; และ &lt;strong&gt;Virtual Mahcine&lt;&#x2F;strong&gt; ที่หลายคนอาจจะเคยเจอ&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งถ้าเราจะใช้ DNS Provider เจ้าอื่นก็ได้ครับ แต่ถ้าเราใช้ Cloudflare เค้าจะมีฟีเจอร์ Proxy ที่ช่วยเสริมความปลอดภัยให้เว็บของเราได้อีกเยอะเลย&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;two-scenarios-overview.jpg&quot; alt=&quot;two-scenarios-overview&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sthaankaarnthii-1-aich-managed-service-yaang-azure-app-service-container-app&quot;&gt;สถานการณ์ที่ 1: ใช้ Managed Service อย่าง Azure App Service &#x2F; Container App&lt;a class=&quot;zola-anchor&quot; href=&quot;#sthaankaarnthii-1-aich-managed-service-yaang-azure-app-service-container-app&quot; aria-label=&quot;Anchor link for: sthaankaarnthii-1-aich-managed-service-yaang-azure-app-service-container-app&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เวลาที่เราพูดถึง &lt;strong&gt;SSL&#x2F;HTTPS&lt;&#x2F;strong&gt; หลายคนอาจนึกถึงการต้องไปขอ certificate เอง ต้องต่ออายุทุกปี ต้องกลัวว่าเดี๋ยววันนึง cert หมดอายุแล้วเว็บจะเข้าไม่ได้… แต่พอเรามาใช้พวก &lt;strong&gt;Managed Service&lt;&#x2F;strong&gt; อย่าง Azure App Service หรือ Azure Container App เนี่ย มันต่างออกไปเลยนะครับ&lt;&#x2F;p&gt;
&lt;p&gt;ลองนึกภาพง่าย ๆ แบบนี้ครับ เรามี web app ตัวหนึ่ง เราเลือก deploy ไปไว้บน Azure App Service … พอเรากดปุ๊บ ตัว App Service นั้นมัน “แถม” HTTPS มาให้เราเลยโดยอัตโนมัติ เราไม่ต้องไปยุ่งกับการขอ cert ไม่ต้องมานั่งจัดการ renewal (ต่ออายุอัตโนมัติ) ไม่ต้องสนใจว่า CA ไหนจะหมดอายุเมื่อไร ทุกอย่าง Azure จัดการให้เสร็จสรรพ&lt;&#x2F;p&gt;
&lt;p&gt;เหมือนคุณซื้อคอนโดแล้วในคอนโดมีระบบรักษาความปลอดภัยครบวงจร มีทั้งยาม กล้องวงจรปิด และคีย์การ์ดพร้อมเสร็จ คุณไม่ต้องไปจ้างยามเอง ไม่ต้องไปเดินติดกล้องเอง ทุกอย่างรวมอยู่ในค่าบริการแล้ว&lt;&#x2F;p&gt;
&lt;p&gt;ทีนี้สมมติว่าเราจะเอา domain ของเราเองมาใช้ สมมติว่าเรามี &lt;code&gt;myapp.com&lt;&#x2F;code&gt; เราอาจจะเอาไปชี้ผ่าน &lt;strong&gt;Cloudflare&lt;&#x2F;strong&gt; สิ่งที่หลายคนจะเจอคือ Cloudflare เองมีโหมดให้เลือกว่าจะให้ทำงานเป็น &lt;strong&gt;DNS only&lt;&#x2F;strong&gt; หรือจะให้ทำงานในแบบ &lt;strong&gt;Proxy Mode&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าดูตัวอย่างจาก Cloudflare Dashboard จะเป็นแบบนี้ครับ เราจะเห็นว่ามันมี &lt;strong&gt;DNS only&lt;&#x2F;strong&gt; กับ &lt;strong&gt;Proxied&lt;&#x2F;strong&gt; ให้เลือก ก็ขึ้นอยู่กับว่าเราต้องการให้ Cloudflare ทำหน้าที่แค่ไหน ซึ่งตรงนี้จะมีผลกับการจัดการ SSL&#x2F;TLS ด้วย แต่ถ้าเป็น DNS Provider เจ้าอื่นๆ ส่วนใหญ่จะมีแค่แบบ DNS only อย่างเดียวครับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;cloudflare-dns-record.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าเราเลือก &lt;strong&gt;DNS only&lt;&#x2F;strong&gt; มันก็ตรงไปตรงมาเลยครับ การเชื่อมต่อของผู้ใช้กับ Azure App Service จะเป็น HTTPS ตามที่ Azure จัดการไว้ให้ทั้งหมด Cloudflare แทบไม่ได้ยุ่งอะไรเลย เป็นเหมือนสมุดโทรศัพท์ที่บอกว่า “อ๋อ myapp.com อยู่ตรงนี้นะ อยู่ IP นี้นะ” แล้วผู้ใช้ก็วิ่งไปหา Azure โดยตรง&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;managed-service-cloudflare-dns-only.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;แต่ถ้าเราเปิด &lt;strong&gt;Proxy Mode&lt;&#x2F;strong&gt; ขึ้นมา เรื่องมันจะสนุกขึ้นอีกหน่อยครับ Proxy Mode จะทำให้ Cloudflare กลายเป็น “ด่านหน้า” ของระบบทั้งหมด เวลามีคนเข้ามาที่ &lt;code&gt;https:&#x2F;&#x2F;myapp.com&lt;&#x2F;code&gt; การเชื่อมต่อ TLS จะถูก terminate ที่ Cloudflare ก่อน จากนั้น Cloudflare จะไปต่อ HTTPS อีกชั้นกับ Azure App Service อีกที&lt;&#x2F;p&gt;
&lt;p&gt;ลองนึกภาพแบบนี้ครับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;managed-service-cloudflare-proxy.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflare กลายเป็นเหมือน รปภ. ด่านหน้าของคอนโดที่เราพูดถึงเมื่อกี้ เวลาแขกเข้ามา เค้าจะต้องเจอ Cloudflare ก่อน Cloudflare จะเช็กบัตร ตรวจสอบว่า request นี้ปลอดภัยไหม มาจาก bot หรือเปล่า ถ้าเรียบร้อยค่อยส่ง request ไปที่ Azure ต่อ&lt;&#x2F;p&gt;
&lt;p&gt;ผลลัพธ์คืออะไร?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;เราได้ทั้ง HTTPS ที่ Azure จัดการให้อยู่แล้ว&lt;&#x2F;li&gt;
&lt;li&gt;เราได้ฟีเจอร์เสริมจาก Cloudflare ไม่ว่าจะเป็น Caching, WAF, Bot protection&lt;&#x2F;li&gt;
&lt;li&gt;และที่สำคัญคือ… เราไม่ต้องปวดหัวกับ certificate ฝั่ง Azure เลย เพราะมัน auto หมด&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ในสถานการณ์นี้เราจะเห็นว่าจริง ๆ การใช้ Managed Service มันช่วยลดความซับซ้อนของ SSL ลงไปเยอะมาก ๆ เพราะ certificate ทั้งหมดถูก manage ให้อัตโนมัติอยู่แล้ว สิ่งเดียวที่เราต้องตัดสินใจคือ “อยากให้ Cloudflare เป็นแค่ DNS เฉย ๆ หรืออยากให้มันเป็น Proxy ที่ช่วยเสริมเกราะป้องกันให้เว็บของเรา” เท่านั้นเอง&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งถ้าเราใช้ Managed Service อย่าง Azure App Service หรือ Container App ผมแนะนำให้เปิด Proxy Mode ไว้เลยครับ เพราะมันได้ประโยชน์เยอะมาก ๆ และแนะนำให้ตั้งค่า SSL&#x2F;TLS ใน Cloudflare เป็นแบบ &lt;strong&gt;Full (Strict)&lt;&#x2F;strong&gt; เพื่อความปลอดภัยสูงสุด สามารถอ่านเพิ่มเติมในในหัวข้อต่อๆ ไปครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;taw-yaangkaartangkhaa-custom-domain-aela-ssl-bn-azure-app-service&quot;&gt;ตัวอย่างการตั้งค่า Custom Domain และ SSL บน Azure App Service&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangkaartangkhaa-custom-domain-aela-ssl-bn-azure-app-service&quot; aria-label=&quot;Anchor link for: taw-yaangkaartangkhaa-custom-domain-aela-ssl-bn-azure-app-service&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;azure-app-service-custom-domain.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;สามารถดูวิธีการตั้งค่า Custom Domain และ SSL บน Azure App Service ได้ที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;app-service&#x2F;app-service-web-tutorial-custom-domain&quot;&gt;Microsoft Docs: Add a custom domain to your app in Azure App Service&lt;&#x2F;a&gt; ครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;taw-yaangkaartangkhaa-custom-domain-aela-ssl-bn-azure-container-app&quot;&gt;ตัวอย่างการตั้งค่า Custom Domain และ SSL บน Azure Container App&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangkaartangkhaa-custom-domain-aela-ssl-bn-azure-container-app&quot; aria-label=&quot;Anchor link for: taw-yaangkaartangkhaa-custom-domain-aela-ssl-bn-azure-container-app&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;azure-container-app-custom-domain.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;สามารถดูวิธีการตั้งค่า Custom Domain และ SSL บน Azure Container App ได้ที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;container-apps&#x2F;custom-domains-managed-certificates?pivots=azure-portal&quot;&gt;Microsoft Docs: Custom domain names and free managed certificates in Azure Container Apps&lt;&#x2F;a&gt; ครับ&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;ซึ่งเวลาที่เราตั้งค่า Custom Domain เสร็จแล้ว Azure จะจัดการเรื่อง SSL ให้เราอัตโนมัติเลย เราไม่ต้องไปขอ cert เอง หรือมานั่งต่ออายุเอง&lt;&#x2F;p&gt;
&lt;p&gt;โดยที่ถ้าเราจะใช้ Cloudflare Proxy Mode เราจะต้องใช้ DNS only ก่อน เพื่อที่เวลาที่ทาง Azure จะ Validate domain ownership เค้าจะใช้วิธีการตรวจสอบผ่าน CNAME หรือ TXT record ที่เราตั้งใน Cloudflare&lt;&#x2F;p&gt;
&lt;p&gt;เมื่อเราตั้งค่า Cloudflare DNS เป็น DNS only แล้ว เราก็ไปตั้งค่า Custom Domain ใน Azure App Service หรือ Container App ได้เลย พอ Azure ตรวจสอบความเป็นเจ้าของโดเมนเสร็จแล้ว เราก็กลับมาเปลี่ยน Cloudflare เป็น Proxy Mode ได้เลย&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;cloudflare-dns-name-check.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;เพราะไม่อย่างนั้น เวลาที่เราเปิด Proxy Mode ทันทีตั้งแต่แรก Azure จะตรวจสอบความเป็นเจ้าของโดเมนไม่ผ่าน Cloudflare จะไม่มี DNS record ที่ Azure ต้องการให้ตรวจสอบ อย่างเช่น ถ้าผมเปิด Proxy Mode&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;cloudflare-dns-record-proxy.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;จะเห็นได้ว่า DNS Record จะไม่สามารถตรวจสอบได้จากภายนอก&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sthaankaarnthii-2-mii-vm-proxy-kh-ngeraae-ng&quot;&gt;สถานการณ์ที่ 2: มี VM + Proxy ของเราเอง&lt;a class=&quot;zola-anchor&quot; href=&quot;#sthaankaarnthii-2-mii-vm-proxy-kh-ngeraae-ng&quot; aria-label=&quot;Anchor link for: sthaankaarnthii-2-mii-vm-proxy-kh-ngeraae-ng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;พอเราขยับจากการใช้ Managed Service ที่สบาย ๆ มาลองดูในโลกที่เราต้องจัดการเองทั้งหมด ภาพมันจะเปลี่ยนไปทันทีครับ สมมติว่าผมมี VM อยู่เครื่องหนึ่ง อาจจะรันอยู่บน Azure, AWS, หรือ DigitalOcean ก็แล้วแต่ เครื่องนี้เราได้มาเปล่า ๆ เลยครับ ไม่มีการจัดการ SSL ให้ ไม่มีระบบ auto renew ให้ ทุกอย่างต้องทำเองหมด&lt;&#x2F;p&gt;
&lt;p&gt;เราสามารถใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SteveLTN&#x2F;https-portal&quot;&gt;https-portal&lt;&#x2F;a&gt; หรือ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;caddyserver.com&#x2F;&quot;&gt;Caddy&lt;&#x2F;a&gt; เข้ามาช่วยจัดการ SSL แบบอัตโนมัติได้เหมือนกันนะครับ เช่นใช้ Let&#x27;s Encrypt เป็น CA แต่เราก็ต้องมีขั้นตอนในการตั้งค่าเอง และดูแลรักษาเอง โดยถ้าเราจะจัดการ Certificate เองเราก็จะสามารถใช้ Cloudflare Proxy Mode ได้เหมือนกันครับ แต่เราก็เพิ่มความซับซ้อนขึ้นมาอีกหน่อย เพราะในเมื่อเราสามารถใช้ประโยชน์จาก Cloudflare Proxy Mode ได้ โดยที่ไม่ต้องมาจัดการ SSL เอง&lt;&#x2F;p&gt;
&lt;p&gt;แต่ในบทความนี้ผมอยากจะเล่าให้ฟังว่า ถ้าเราไม่อยากจัดการ SSL เอง เราจะทำยังไงให้มันง่ายขึ้น โดยใช้ Cloudflare เป็นตัวช่วย เป็น Proxy และไม่ต้องจัดการ Renewal เอง ในขณะที่เรายังสามารถใช้งานได้อย่างปลอดภัย ในโหมด &lt;strong&gt;Full (Strict)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ทีนี้ใน VM เครื่องนั้นเราก็อาจจะติดตั้ง proxy ขึ้นมาตัวหนึ่ง อาจจะเป็น Nginx, HAProxy หรืออะไรก็ได้ เพื่อทำหน้าที่เป็นด่านหน้าของแอปพลิเคชันทั้งหมด แล้วเราก็อยากเอา VM เครื่องนี้ไปผูกกับ &lt;strong&gt;Cloudflare&lt;&#x2F;strong&gt; ให้ผู้ใช้เข้าผ่าน domain &lt;code&gt;myapp.com&lt;&#x2F;code&gt; เหมือนเดิม&lt;&#x2F;p&gt;
&lt;p&gt;จุดที่เริ่มมีคำถามคือ… แล้วเราจะทำยังไงกับ SSL ที่ origin (ฝั่ง VM) ดี?&lt;&#x2F;p&gt;
&lt;p&gt;ลองนึกภาพเวลา user เข้ามาที่ &lt;code&gt;https:&#x2F;&#x2F;myapp.com&lt;&#x2F;code&gt; ครับ ถ้าเราเปิด Proxy Mode ที่ Cloudflare การเชื่อมต่อ TLS จะถูก terminate ที่ Cloudflare ก่อนหนึ่งรอบ จากนั้น Cloudflare จะไปสร้างการเชื่อมต่อใหม่ไปหา origin ของเรา ทีนี้เองที่ Cloudflare จะ “เลือก” ว่าจะเชื่อ origin หรือไม่&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ลองดูภาพนี้นะครับ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;vm-proxy.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ตรง “???“ นี่แหละครับที่เป็นเงื่อนไขสำคัญ ว่าจริง ๆ แล้ว Cloudflare จะไปคุยกับ VM ของเราแบบไหน ขึ้นกับโหมดที่เราเลือกใน Cloudflare&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cloudflare-proxy-mode-flexible&quot;&gt;Cloudflare Proxy Mode: Flexible&lt;a class=&quot;zola-anchor&quot; href=&quot;#cloudflare-proxy-mode-flexible&quot; aria-label=&quot;Anchor link for: cloudflare-proxy-mode-flexible&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ถ้าเราเลือก &lt;strong&gt;Flexible&lt;&#x2F;strong&gt; มันจะเป็นแบบนี้&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;cloudflare-flexible.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflare บังคับ terminate TLS ที่ตัวเอง แต่เวลาไปหา origin กลับวิ่ง HTTP ธรรมดา ไม่ต้องมี cert ใด ๆ ที่ VM เลย ถึงจะดูง่าย แต่จริง ๆ อันตรายมาก เพราะการเชื่อมต่อ Cloudflare → VM ไม่ได้เข้ารหัส&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cloudflare-proxy-mode-full&quot;&gt;Cloudflare Proxy Mode: Full&lt;a class=&quot;zola-anchor&quot; href=&quot;#cloudflare-proxy-mode-full&quot; aria-label=&quot;Anchor link for: cloudflare-proxy-mode-full&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ถ้าเราเลือก &lt;strong&gt;Full&lt;&#x2F;strong&gt; ภาพจะเปลี่ยนเป็น&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;cloudflare-full.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;VM ของเราต้องมี cert อยู่ แต่จะเป็น self-signed ก็ได้ Cloudflare จะไม่เช็กว่า cert นั้นถูกต้องไหม แค่เจอ TLS ก็คุยต่อได้แล้ว อันนี้ก็พอช่วยให้การสื่อสารเข้ารหัสครบทุก hop แต่ถ้ามีใครปลอม cert ระหว่างทาง Cloudflare ก็ไม่รู้&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cloudflare-proxy-mode-full-strict&quot;&gt;Cloudflare Proxy Mode: Full (Strict)&lt;a class=&quot;zola-anchor&quot; href=&quot;#cloudflare-proxy-mode-full-strict&quot; aria-label=&quot;Anchor link for: cloudflare-proxy-mode-full-strict&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;และสุดท้าย ถ้าเราเลือก &lt;strong&gt;Full (Strict)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;cloudflare-full-strict.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;รอบนี้ Cloudflare จะยอมคุยกับ VM ของเราก็ต่อเมื่อ VM มี cert ที่ถูกต้องเท่านั้น จะเป็น cert จาก CA ทั่วไป (เช่น Let’s Encrypt) หรือจะเป็น &lt;strong&gt;Cloudflare Origin Certificate&lt;&#x2F;strong&gt; ที่ออกมาใช้กับ Cloudflare โดยตรงก็ได้&lt;&#x2F;p&gt;
&lt;p&gt;โดยเราสามารถตั้งค่าโหมด SSL&#x2F;TLS ได้ที่เมนู SSL&#x2F;TLS ใน Cloudflare Dashboard ครับ ซึ่งอันนี้ตัวอย่างจะเป็นการตั้งค่าแบบ Full (Strict)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;cloudflare-ssl-tls-full-strict.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;พอเล่ามาถึงตรงนี้ หลายคนน่าจะเห็นแล้วว่าความแตกต่างระหว่างโหมด Flexible, Full และ Full (Strict) มันอยู่ตรง &lt;strong&gt;ความไว้ใจ (Trust)&lt;&#x2F;strong&gt; ที่ Cloudflare มีต่อ cert ของเรา ถ้าเป็น Flexible ก็ไม่ต้องมีเลย ถ้าเป็น Full แค่พอมี TLS ก็พอใจ แต่ถ้า Strict ต้องมี cert จริงเท่านั้นถึงจะผ่าน&lt;&#x2F;p&gt;
&lt;p&gt;และในโลกจริง ๆ เวลาเรามี VM ของตัวเอง สิ่งที่แนะนำคือใช้ &lt;strong&gt;Cloudflare Origin Certificate&lt;&#x2F;strong&gt; ครับ เราสามารถ generate cert จาก Cloudflare แล้วเอาไปติดตั้งที่ VM ได้เลย แล้ว Cloudflare ก็จะเชื่อมต่อเข้ามาแบบ Strict ได้เต็มที่ ปลอดภัยทั้งสองฝั่ง&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;พอเปรียบเทียบกับสถานการณ์แรกจะเห็นชัดว่า การใช้ Managed Service เราแทบไม่ต้องคิดเรื่อง cert เลย Azure จัดการให้ แต่พอเป็น VM เอง เราต้องจัดการทุกอย่างเองตั้งแต่การ generate, ติดตั้ง ไปจนถึงการต่ออายุ cert ซึ่งตรงนี้แหละครับที่ทำให้หลายคนมองว่า SSL เป็นเรื่อง “ยุ่งยาก” …แต่จริง ๆ ถ้าเราเข้าใจ diagram การไหลของ TLS แค่ไม่กี่แบบนี้ ทุกอย่างจะเริ่มชัดขึ้นทันที&lt;&#x2F;p&gt;
&lt;h2 id=&quot;taw-yaang-kaarsraang-csr-aelatidtang-cloudflare-origin-certificate-bn-nginx&quot;&gt;ตัวอย่าง: การสร้าง CSR และติดตั้ง Cloudflare Origin Certificate บน Nginx&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaang-kaarsraang-csr-aelatidtang-cloudflare-origin-certificate-bn-nginx&quot; aria-label=&quot;Anchor link for: taw-yaang-kaarsraang-csr-aelatidtang-cloudflare-origin-certificate-bn-nginx&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ทีนี้พอเราเล่ามาถึงตรงนี้ หลายคนอาจสงสัยว่า “แล้วในโลกจริง ๆ เวลาจะขอ certificate จาก Cloudflare ต้องทำยังไง?” เรื่องนี้ถ้าอธิบายแบบนามธรรมอาจจะยังไม่เห็นภาพ ผมเลยอยากยกตัวอย่างที่ง่ายที่สุด นั่นก็คือการใช้ &lt;strong&gt;Nginx&lt;&#x2F;strong&gt; เป็น proxy ของเราเอง แล้วติดตั้ง &lt;strong&gt;Cloudflare Origin Certificate&lt;&#x2F;strong&gt; ให้มันครับ&lt;&#x2F;p&gt;
&lt;p&gt;ลองนึกภาพตามกันครับ เรามี VM อยู่เครื่องหนึ่ง สมมติว่า IP เป็น &lt;code&gt;1.2.3.4&lt;&#x2F;code&gt; และเรามีโดเมน &lt;code&gt;myapp.com&lt;&#x2F;code&gt; ที่ชี้ไปหา IP เครื่องนี้แล้ว ทีนี้เราจะผูกมันเข้ากับ Cloudflare และเปิดโหมด &lt;strong&gt;Full (Strict)&lt;&#x2F;strong&gt; ให้ Cloudflare เชื่อมต่อกับ VM ได้อย่างปลอดภัย&lt;&#x2F;p&gt;
&lt;p&gt;ก่อนอื่น สิ่งที่เราต้องมีคือ &lt;strong&gt;Private Key + CSR (Certificate Signing Request)&lt;&#x2F;strong&gt;
การสร้าง CSR ก็เหมือนการไปทำ “ใบคำขอ” ที่เราจะยื่นต่อ CA ว่า เราคือเจ้าของโดเมนนี้นะ ออก cert ให้เราหน่อย&lt;&#x2F;p&gt;
&lt;p&gt;บน VM เราก็รันคำสั่งนี้:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;openssl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; req&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;newkey&lt;&#x2F;span&gt; rsa:2048&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;nodes&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;  -&lt;&#x2F;span&gt;keyout&lt;&#x2F;span&gt; myapp.com.key &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;  -&lt;&#x2F;span&gt;out&lt;&#x2F;span&gt; myapp.com.csr &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;  -&lt;&#x2F;span&gt;subj&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;CN=myapp.com&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;พอรันเสร็จ เราจะได้สองไฟล์&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;myapp.com.key&lt;&#x2F;code&gt; → กุญแจส่วนตัว (ต้องเก็บไว้ที่ origin)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;myapp.com.csr&lt;&#x2F;code&gt; → คำขอ cert ที่เอาไปยื่นกับ Cloudflare&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ทีนี้เราก็เปิดหน้า Cloudflare Dashboard ไปที่เมนู SSL&#x2F;TLS → Origin Certificates แล้วกด “Create Certificate”
Cloudflare จะให้เราเลือกว่าจะใช้แบบ &lt;strong&gt;generate auto&lt;&#x2F;strong&gt; หรือจะเอา CSR ของเราไปใส่ก็ได้
สมมติเราอัปโหลด &lt;code&gt;myapp.com.csr&lt;&#x2F;code&gt; เข้าไป Cloudflare ก็จะออกไฟล์ &lt;code&gt;myapp.com.crt&lt;&#x2F;code&gt; คืนมาให้&lt;&#x2F;p&gt;
&lt;p&gt;ตรงนี้แหละครับที่สำคัญ เพราะ &lt;code&gt;myapp.com.crt&lt;&#x2F;code&gt; ตัวนี้ Cloudflare ลงนามให้เรียบร้อยแล้ว Cloudflare เองก็เลย “ยอมเชื่อ” cert ตัวนี้เสมอ&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;พอเราได้ cert มาแล้ว เราก็เอาไฟล์ &lt;code&gt;myapp.com.crt&lt;&#x2F;code&gt; กับ &lt;code&gt;myapp.com.key&lt;&#x2F;code&gt; ไปวางใน VM จากนั้นก็ไปแก้ config ของ Nginx ให้มันฟังพอร์ต 443&lt;&#x2F;p&gt;
&lt;p&gt;สมมติว่าเรามีไฟล์ config แบบง่าย ๆ ชื่อ &lt;code&gt;&#x2F;etc&#x2F;nginx&#x2F;sites-available&#x2F;myapp.conf&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nginx&quot; class=&quot;language-nginx z-code&quot;&gt;&lt;code class=&quot;language-nginx&quot; data-lang=&quot;nginx&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;server {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    listen 443 ssl;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    server_name myapp.com;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    ssl_certificate     &#x2F;etc&#x2F;nginx&#x2F;ssl&#x2F;myapp.com.crt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    ssl_certificate_key &#x2F;etc&#x2F;nginx&#x2F;ssl&#x2F;myapp.com.key;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    location &#x2F; {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        proxy_pass http:&#x2F;&#x2F;127.0.0.1:3000;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แล้วก็เปิดพอร์ต 80 ไว้ redirect ไป 443 อีกทีเพื่อบังคับ HTTPS&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nginx&quot; class=&quot;language-nginx z-code&quot;&gt;&lt;code class=&quot;language-nginx&quot; data-lang=&quot;nginx&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;server {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    listen 80;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    server_name myapp.com;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    return 301 https:&#x2F;&#x2F;$host$request_uri;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้น reload nginx:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nginx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;t&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; reload nginx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;พอถึงตรงนี้ flow จะกลายเป็นแบบนี้ครับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;ssl-tls-made-easy-cloudflare-azure&#x2F;cloudflare-origin-ca.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflare terminate TLS ที่ตัวเองก่อน แล้วก็เชื่อมต่อ HTTPS ต่อไปที่ Nginx อีกที
ทีนี้ Cloudflare จะเชื่อ cert ของเราแน่นอน เพราะ cert ตัวนี้มันเป็น &lt;strong&gt;Origin CA ที่ Cloudflare ออกเอง&lt;&#x2F;strong&gt;
ดังนั้นเราสามารถเปิดโหมด &lt;strong&gt;Full (Strict)&lt;&#x2F;strong&gt; ได้อย่างมั่นใจเลย&lt;&#x2F;p&gt;
&lt;p&gt;และนี่คือ &lt;strong&gt;ภาพของการใช้ CSR + Origin CA จริง ๆ&lt;&#x2F;strong&gt; ที่เราเจอกันในโลก production
บางทีเวลาอ่านทฤษฎี SSL มันอาจดูเป็นอะไรที่ไกลตัว แต่พอเราลองทำด้วยตัวเองสักครั้ง แล้วเห็นว่าจริง ๆ มันก็เป็นแค่ “ออกกุญแจ → ส่งคำขอ → ได้ใบ cert กลับมา → ใส่ไว้ใน proxy” … ความยุ่งยากที่เคยคิดว่ามันเป็นหลุมดำ ก็จะเริ่มคลี่คลายออกไปทีละนิดครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cloudflare-origin-ca&quot;&gt;Cloudflare origin CA&lt;a class=&quot;zola-anchor&quot; href=&quot;#cloudflare-origin-ca&quot; aria-label=&quot;Anchor link for: cloudflare-origin-ca&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;พอเราได้ลองทำงานกับ &lt;strong&gt;Cloudflare Origin Certificate&lt;&#x2F;strong&gt; จริง ๆ เราจะเห็นเลยว่ามันช่วยลดภาระชีวิตเราได้เยอะมาก ๆ เลยครับ เพราะถ้าเราไปใช้พวก Let’s Encrypt ปกติ เราอาจต้องคอยต่ออายุทุก 90 วัน หรือต้องคอยตั้ง automation ให้มัน renew เอง ไม่งั้นวันดีคืนดีเว็บเข้าไม่ได้เพราะ cert หมดอายุ&lt;&#x2F;p&gt;
&lt;p&gt;แต่ Origin CA ของ Cloudflare ไม่เหมือนกัน จุดเด่นเลยคือ &lt;strong&gt;อายุยาวมาก&lt;&#x2F;strong&gt; …ยาวเป็นสิบปีครับ เรียกได้ว่าพอออกมาแล้ว เราสามารถวางใจได้เลยว่า เราไม่ต้องมานั่งวิ่งวุ่นต่ออายุทุก ๆ ไตรมาส ชีวิตก็เบาขึ้นไปเยอะ&lt;&#x2F;p&gt;
&lt;p&gt;ดังนั้นเวลาที่เราเปิดโหมด &lt;strong&gt;Full (Strict)&lt;&#x2F;strong&gt; กับ Cloudflare แล้วใช้ Origin CA ที่ออกโดย Cloudflare เอง มันก็เลยเป็นเหมือนการจับคู่ที่ลงตัวสุด ๆ คือฝั่ง Cloudflare ก็ยอมเชื่อ cert นี้เสมอ เพราะมันเป็นของที่ตัวเองออก ส่วนฝั่งเราก็ไม่ต้องกังวลเรื่อง renewal บ่อย ๆ&lt;&#x2F;p&gt;
&lt;p&gt;อ่านเพิ่มเติมได้ที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;ssl&#x2F;origin-configuration&#x2F;origin-ca&#x2F;&quot;&gt;Cloudflare: What is an Origin CA certificate?&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;หรือถ้าใครไม่อยากกดผ่านหน้า Cloudflare Dashboard ก็สามารถใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;api&#x2F;resources&#x2F;origin_ca_certificates&#x2F;methods&#x2F;create&#x2F;&quot;&gt;Cloudflare API&lt;&#x2F;a&gt; สร้าง Origin CA ได้เหมือนกันครับ สะดวกมากๆ ครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;srup&quot;&gt;สรุป&lt;a class=&quot;zola-anchor&quot; href=&quot;#srup&quot; aria-label=&quot;Anchor link for: srup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เรื่อง SSL&#x2F;TLS ถ้ามองผิวเผินมันอาจจะดูเหมือนเป็น “หลุมดำ” ที่เต็มไปด้วยศัพท์เทคนิคและขั้นตอนที่ซับซ้อน แต่จริง ๆ แล้วถ้าเราค่อย ๆ แยกแยะเป็นสถานการณ์ เราจะเห็นว่ามันไม่ได้ซับซ้อนอย่างที่คิด&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ถ้าเราใช้ &lt;strong&gt;Managed Service&lt;&#x2F;strong&gt; อย่าง Azure App Service หรือ Container App ทุกอย่างแทบจะถูกจัดการให้หมด เราแทบไม่ต้องแตะเรื่อง certificate เลย แค่เลือกว่าจะให้ Cloudflare ทำหน้าที่เป็น DNS เฉย ๆ หรือ Proxy เสริมก็พอ&lt;&#x2F;li&gt;
&lt;li&gt;แต่ถ้าเราใช้ &lt;strong&gt;VM + Proxy เอง&lt;&#x2F;strong&gt; เรื่อง certificate จะกลายเป็นสิ่งที่เราต้องรับผิดชอบเองเต็ม ๆ ซึ่งถ้าเลือกใช้ &lt;strong&gt;Cloudflare Origin CA&lt;&#x2F;strong&gt; แล้วเปิดโหมด &lt;strong&gt;Full (Strict)&lt;&#x2F;strong&gt; เราก็จะได้ทั้งความปลอดภัยครบ และความสบายใจเพราะไม่ต้องคอยต่ออายุ cert บ่อย ๆ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;สุดท้ายแล้ว การเข้าใจ flow ของ TLS termination ว่าเกิดขึ้นตรงไหนบ้าง ใครเชื่อใคร และ certificate ตัวไหนที่ Cloudflare ยอมรับ …สิ่งเหล่านี้จะช่วยให้เรามีความมั่นใจมากขึ้นในการ setup HTTPS ของตัวเอง&lt;&#x2F;p&gt;
&lt;p&gt;จากที่เคยรู้สึกว่า SSL เป็นเรื่องยุ่งยาก พอเราเห็นภาพและได้ลองลงมือจริง มันก็แค่การสร้างกุญแจ ขอใบรับรอง และเอาไปวางให้ proxy ใช้เท่านั้นเองครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ลองใช้ Bun สร้าง Docker image บน Colima x86 และ Mac Arm64 (M Series) แล้วเจอปัญหาแบบไม่คาดคิด</title>
		<published>2025-05-17T00:00:00+00:00</published>
		<updated>2025-05-17T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/bun-docker-colima-x86-on-mac-arm64-issue/" type="text/html"/>
		<id>https://thadaw.com/posts/bun-docker-colima-x86-on-mac-arm64-issue/</id>
		<content type="html">&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;bun-docker-colima-x86-on-mac-arm64-issue&#x2F;cover.jpg&quot; alt=&quot;cover&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;สรุปสั้น ๆ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;p&gt;ลองใช้ Bun สร้าง Docker image บน Colima (x86) แล้วเจอปัญหา crash แบบเงียบ ๆ เพราะ binary ของ Bun ไม่ compatible กับ QEMU โดยเจอ Error แบบเงียบๆ ว่า Illegal instruction&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ช่วงนี้ผมมีโปรเจกต์เล็ก ๆ ที่กำลังทำอยู่ เป็น Slack Bot ที่เขียนด้วย TypeScript
เลยมีความคิดว่า… ถ้าลองย้าย runtime จาก Node.js มาเป็น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;bun.sh&quot;&gt;Bun&lt;&#x2F;a&gt; จะดีขึ้นแค่ไหน?&lt;&#x2F;p&gt;
&lt;p&gt;Bun มันน่าสนใจตรงที่:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;เร็วกว่า Node แบบรู้สึกได้&lt;&#x2F;li&gt;
&lt;li&gt;ใช้แทนทั้ง runtime, bundler และ test runner ได้ในตัว&lt;&#x2F;li&gt;
&lt;li&gt;คำสั่งก็สั้นดี ไม่ต้องแยกใช้ &lt;code&gt;node&lt;&#x2F;code&gt;, &lt;code&gt;ts-node&lt;&#x2F;code&gt; หรือพวก bundler เพิ่มเติม&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;พอเห็น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;hub.docker.com&#x2F;r&#x2F;oven&#x2F;bun&quot;&gt;docker image อย่างเป็นทางการของ Bun&lt;&#x2F;a&gt; ก็ยิ่งรู้สึกว่า “น่าจะใช้กับ production ได้ไม่ยาก”
เลยตั้งใจจะลอง build Docker image ของแอปตัวเองด้วย Bun ให้ได้แบบ production-ready แล้วเอาไป deploy ผ่าน Colima ที่ผมใช้บน Mac M1&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งก็คิดไว้ในใจว่า…&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“ถ้า build เป็น x86 แล้วใช้ Colima จำลอง x86 ด้วย ก็น่าจะ run ได้แหละมั้ง?”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;แน่นอนครับ ว่าชีวิตจริงมันไม่ได้ง่ายขนาดนั้น 555&lt;&#x2F;p&gt;
&lt;h2 id=&quot;t-nthiil-ngtham&quot;&gt;ตอนที่ลองทำ&lt;a class=&quot;zola-anchor&quot; href=&quot;#t-nthiil-ngtham&quot; aria-label=&quot;Anchor link for: t-nthiil-ngtham&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ผมเริ่มจากเขียน &lt;code&gt;Dockerfile&lt;&#x2F;code&gt; ง่าย ๆ ที่ใช้ base image ของ Bun โดยตรง
เพื่อให้ image มีขนาดเล็กที่สุด เลยเลือกใช้ &lt;code&gt;oven&#x2F;bun:alpine&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;Dockerfile&quot; class=&quot;language-Dockerfile z-code&quot;&gt;&lt;code class=&quot;language-Dockerfile&quot; data-lang=&quot;Dockerfile&quot;&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Build base
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; oven&#x2F;bun:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;alpine&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;AS&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;base&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;usr&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Install dev dependencies (cached)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; base &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;AS&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;install&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;mkdir -p &#x2F;temp&#x2F;dev
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; package.json bun.lock &#x2F;temp&#x2F;dev&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;cd &#x2F;temp&#x2F;dev &amp;amp;&amp;amp; bun install --frozen-lockfile
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Install production dependencies
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;mkdir -p &#x2F;temp&#x2F;prod
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; package.json bun.lock &#x2F;temp&#x2F;prod&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;cd &#x2F;temp&#x2F;prod &amp;amp;&amp;amp; bun install --frozen-lockfile --production
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Copy source code and dev dependencies
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; base &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;AS&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;prerelease&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;install&lt;&#x2F;span&gt; &#x2F;temp&#x2F;dev&#x2F;node_modules node_modules
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; . .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; base &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;AS&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;release&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;usr&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Copy prod dependencies and source file
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;install&lt;&#x2F;span&gt; &#x2F;temp&#x2F;prod&#x2F;node_modules node_modules
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;prerelease&lt;&#x2F;span&gt; &#x2F;usr&#x2F;app .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;prerelease&lt;&#x2F;span&gt; &#x2F;usr&#x2F;app&#x2F;package.json .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;USER &lt;&#x2F;span&gt;bun
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;EXPOSE &lt;&#x2F;span&gt;3000
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-dockerfile&quot;&gt;ENTRYPOINT &lt;&#x2F;span&gt;[&lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;bun&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;run&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;src&#x2F;main.ts&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นใช้ GitHub Actions เป็นตัว build และ push image ขึ้น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;container-registry&#x2F;&quot;&gt;Azure Container Registry (ACR)&lt;&#x2F;a&gt; แบบ private
ตัว pipeline ก็ไม่ได้ซับซ้อนอะไร ใช้แค่ &lt;code&gt;docker&#x2F;build-push-action&lt;&#x2F;code&gt; แล้ว tag เป็น &lt;code&gt;latest&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ตัวอย่าง GitHub Actions ก็ประมาณนี้ ใช้ Cache บน GitHub Actions ด้วยนะ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Build Docker Image with Bun &amp;amp; Check Size&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-constant z-language z-boolean z-yaml&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;branches&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-flow-sequence z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-sequence z-begin z-yaml&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-in z-yaml&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-sequence z-end z-yaml&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;pull_request&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;branches&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-flow-sequence z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-sequence z-begin z-yaml&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-in z-yaml&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-sequence z-end z-yaml&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;IMAGE_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;ai-platform&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;IMAGE_TAG&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;latest&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;runs-on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;ubuntu-latest&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;steps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Checkout repository&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;actions&#x2F;checkout@v4&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Set up Docker Buildx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;docker&#x2F;setup-buildx-action@v3&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Cache Docker layers&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;actions&#x2F;cache@v4&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&#x2F;tmp&#x2F;.buildx-cache&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ runner.os }}-buildx-${{ github.sha }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;restore-keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-block-scalar z-literal z-yaml&quot;&gt;|&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;            ${{ runner.os }}-buildx-
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;&lt;&#x2F;span&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Log in to Azure Container Registry&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;docker&#x2F;login-action@v3&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;registry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets.ACR_LOGIN_SERVER }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;username&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets.ACR_USERNAME }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;password&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets.ACR_PASSWORD }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Build Docker image&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;docker&#x2F;build-push-action@v5&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-decimal z-yaml&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;.&#x2F;Dockerfile&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-yaml&quot;&gt;true&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Automatically push the image to the registry
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;load&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-yaml&quot;&gt;true&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Set true when we want to see the image in the local docker, example: check image size
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;tags&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets.ACR_LOGIN_SERVER }}&#x2F;${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;cache-from&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;type=local,src=&#x2F;tmp&#x2F;.buildx-cache&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;cache-to&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;type=local,dest=&#x2F;tmp&#x2F;.buildx-cache-new,mode=max&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Move cache&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-block-scalar z-literal z-yaml&quot;&gt;|&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;          rm -rf &#x2F;tmp&#x2F;.buildx-cache
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;          mv &#x2F;tmp&#x2F;.buildx-cache-new &#x2F;tmp&#x2F;.buildx-cache
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;พอ build เสร็จ ผมก็ไปฝั่ง local ที่ใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;abiosoft&#x2F;colima&quot;&gt;Colima&lt;&#x2F;a&gt; บน Mac M1
ซึ่งปกติจะรันเป็น &lt;code&gt;arm64&lt;&#x2F;code&gt; แต่คราวนี้อยากเทสต์ให้แน่ใจว่า image แบบ &lt;code&gt;x86_64&lt;&#x2F;code&gt; จะรันได้แน่ ๆ
เลยสั่ง start แบบระบุ architecture ไปเลย:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;colima&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; start&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;arch&lt;&#x2F;span&gt; x86_64&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นก็ลองดึง image ที่ build ไว้ขึ้นมารันด้วย &lt;code&gt;docker compose&lt;&#x2F;code&gt;
เพื่อให้แน่ใจว่าใช้ของใหม่จริง ๆ ก็ใส่ &lt;code&gt;--pull always&lt;&#x2F;code&gt; ไปด้วย:&lt;&#x2F;p&gt;
&lt;p&gt;ตัวอย่าง &lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt; ก็ประมาณนี้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;services&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;my-azure-acr.azurecr.io&#x2F;ai-platform:latest&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;env_file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;.env&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Load from .env file like dotenv
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;ports&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;${PORT}:${PORT}&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;   &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Use the same port as in .env
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;volumes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;ai-data:&#x2F;usr&#x2F;app&#x2F;.data&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;restart&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;unless-stopped&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;volumes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;ai-data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนนั้นก็ลองรันด้วยคำสั่ง:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; compose up&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;d&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;pull&lt;&#x2F;span&gt; always&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ณ จุดนี้ ทุกอย่างดูเหมือนจะโอเคนะ…
Build ผ่าน, Push สำเร็จ, Image ดึงลงมาได้, Container ก็ดูเหมือนจะ start แล้ว…&lt;&#x2F;p&gt;
&lt;p&gt;แต่ความเงียบผิดปกติก็เริ่มขึ้นตรงนี้แหละ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aelwmankphangaebbengiiyb&quot;&gt;แล้วมันก็พังแบบเงียบ ๆ&lt;a class=&quot;zola-anchor&quot; href=&quot;#aelwmankphangaebbengiiyb&quot; aria-label=&quot;Anchor link for: aelwmankphangaebbengiiyb&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลังจากสั่ง &lt;code&gt;docker compose up -d&lt;&#x2F;code&gt; แล้วทุกอย่างดูเหมือนจะปกติ ผมก็ลองดูสถานะ container ด้วยคำสั่ง:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ps&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;สิ่งที่เจอคือ container ขึ้นจริง แต่ขึ้นแค่แป๊บเดียวแล้วเข้าโหมด:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Restarting (132) every few seconds
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ลองดู log ด้วย:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; logs &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;container-id&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;...ไม่มีอะไรออกมาเลยครับ โล่งมาก&lt;&#x2F;p&gt;
&lt;p&gt;เข้าใจว่า &quot;อาจจะ crash ก่อนจะเขียน log ทัน&quot; เลยลอง shell เข้าไปดูด้วย:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; exec&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;it&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;container-id&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; sh&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ลองรัน &lt;code&gt;bun --version&lt;&#x2F;code&gt; ดูแบบไม่คิดอะไรมาก:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;bun --version
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แล้วก็เจอคำตอบของทุกอย่างตรงนี้เลยครับ:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Illegal instruction
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;คือ binary ของ Bun (ใน image &lt;code&gt;oven&#x2F;bun:alpine&lt;&#x2F;code&gt;) มันใช้ instruction บางอย่างที่ QEMU ใน Colima รันไม่ได้
แม้ว่าผมจะ start Colima แบบ &lt;code&gt;--arch x86_64&lt;&#x2F;code&gt; แล้วก็ตาม&lt;&#x2F;p&gt;
&lt;p&gt;ผมลองเปลี่ยนไปใช้ image &lt;code&gt;oven&#x2F;bun:1&lt;&#x2F;code&gt; ที่เป็น tag หลัก ก็เจอปัญหาเดียวกันเป๊ะ&lt;&#x2F;p&gt;
&lt;p&gt;พอถึงตรงนี้ก็เลยชัดเจนว่า...&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Bun บน Colima (แม้จะจำลอง x86) ยังรันไม่ได้แน่ ๆ ไม่ว่าจะใช้ image แบบ alpine หรือ full tag ก็ตาม
ถึงจะ build มาแบบ x86 แล้วก็เถอะ ถ้า run-time มันไม่ support instruction นั้น → ก็พังอยู่ดี&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ได้เลยจ้า! ปลายฟ้าปรับ Section 4 ให้ใหม่แบบไม่พูดถึง Docker Desktop ตามที่มายต้องการ
กระชับ ตรงประเด็น และยังคงโทนเล่าเรื่องสบาย ๆ เหมือนเดิม:&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aelweraacchaaekyangaingdii&quot;&gt;แล้วเราจะแก้ยังไงดี&lt;a class=&quot;zola-anchor&quot; href=&quot;#aelweraacchaaekyangaingdii&quot; aria-label=&quot;Anchor link for: aelweraacchaaekyangaingdii&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;พอรู้ว่า Bun รันบน Colima ไม่ได้ ก็เลยลองไล่หาทางแก้
โดยยังอยากคงแนวทางเดิมไว้ให้ใกล้เคียง production จริงมากที่สุด&lt;&#x2F;p&gt;
&lt;p&gt;สิ่งแรกที่ลองคือเปลี่ยนจาก &lt;code&gt;oven&#x2F;bun:alpine&lt;&#x2F;code&gt; มาใช้ &lt;code&gt;oven&#x2F;bun:1&lt;&#x2F;code&gt;
ซึ่งเป็น base image แบบเต็มที่ขนาดใหญ่ขึ้น (ไม่ใช่ alpine)
แต่ก็ยังเจอปัญหา &lt;code&gt;Illegal instruction&lt;&#x2F;code&gt; เหมือนเดิม
สรุปคือ &lt;strong&gt;ทั้งสอง image ยังใช้ binary ที่ QEMU ใน Colima รันไม่ได้&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;สุดท้ายเลยตัดสินใจเปลี่ยน base image จาก Bun กลับมาใช้ Node.js
แค่เพื่อให้รันบน Colima ได้ แล้วค่อยไป optimize เรื่องขนาด image อีกที
อย่างน้อยก็ได้ test flow ของระบบต่อได้ก่อน ไม่ต้องติดที่ runtime&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ส่วนเรื่อง image size ยังใหญ่เพราะ &lt;code&gt;node_modules&lt;&#x2F;code&gt; ต้อง COPY เข้าไปทั้งก้อน — อันนี้ยังไม่ได้แก้ตอนนี้ครับ&lt;&#x2F;strong&gt;
เดี๋ยวไว้ blog หน้าจะมาชวนคุยต่อว่า ถ้าเราทำการ bundle ก่อน (เช่นด้วย &lt;code&gt;esbuild&lt;&#x2F;code&gt; หรือ &lt;code&gt;bun bun&lt;&#x2F;code&gt;)
เราจะลดขนาด image ลงได้ขนาดไหน และยังมีวิธีแยก native modules ออกได้ยังไงบ้าง&lt;&#x2F;p&gt;
&lt;p&gt;มาแล้วจ้า! นี่คือ &lt;strong&gt;Section 5: บทเรียน &amp;amp; ชวนคิดต่อ&lt;&#x2F;strong&gt;
เป็นตอนจบของโพสต์นี้ ที่สรุปสิ่งที่เจอ พร้อมโยนคำถามเบา ๆ ทิ้งท้ายให้คนอ่านได้คิดต่อ:&lt;&#x2F;p&gt;
&lt;h2 id=&quot;btheriiyn&quot;&gt;บทเรียน&lt;a class=&quot;zola-anchor&quot; href=&quot;#btheriiyn&quot; aria-label=&quot;Anchor link for: btheriiyn&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;พอลองมาทั้งหมด สรุปสั้น ๆ ได้ว่า…&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Bun น่าสนใจมาก แต่ตอนนี้ยังมีข้อจำกัดเรื่อง compatibility กับบาง runtime environment อย่าง QEMU บน Colima&lt;&#x2F;li&gt;
&lt;li&gt;ต่อให้ build ด้วย x86 และระวังเรื่อง architecture แล้ว แต่ถ้า binary ใช้ instruction ที่ layer ข้างล่างสุดไม่รองรับ → ก็รันไม่ได้อยู่ดี&lt;&#x2F;li&gt;
&lt;li&gt;เวลาเจอปัญหาพวกนี้ สิ่งที่ยากกว่าการแก้คือ…การหาว่ามันพังเพราะอะไร
เพราะบางครั้ง log ก็ไม่มี, error ก็ไม่บอก, ทุกอย่างดูเหมือนปกติแต่ run ไม่ได้&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;และที่สำคัญคือ…&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;การ optimize ขนาด image ยังไม่จบแค่นี้
แค่ใช้ Bun แล้ว build image → ยังไม่ได้ image ที่เบาแบบที่หวังไว้
เพราะ &lt;code&gt;bun install&lt;&#x2F;code&gt; ยังต้องพา &lt;code&gt;node_modules&lt;&#x2F;code&gt; ทั้งก้อนไปด้วย&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ถ้าอยากลดขนาดจริง ๆ — ต้องเปลี่ยน mindset จาก “run source ตรง ๆ” → มาเป็น “bundle ให้จบก่อนค่อย COPY เข้า image”&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งเดี๋ยว blog หน้าผมจะมาเล่าต่อเรื่องนี้
รวมถึงเปรียบเทียบว่าใช้ &lt;code&gt;esbuild&lt;&#x2F;code&gt; หรือ &lt;code&gt;bun bun&lt;&#x2F;code&gt; ช่วย bundle แล้วขนาดลดลงแค่ไหน
และจะมีแนวทางแยก native module อย่างไรให้เหลือเบาที่สุด&lt;&#x2F;p&gt;
&lt;h2 id=&quot;mumchwnkhid&quot;&gt;มุมชวนคิด&lt;a class=&quot;zola-anchor&quot; href=&quot;#mumchwnkhid&quot; aria-label=&quot;Anchor link for: mumchwnkhid&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ใครเคยเจอปัญหาอะไรคล้าย ๆ แบบนี้บ้าง?
หรือเคยต้อง debug อะไรที่ crash เงียบ ๆ บน container แล้วไม่มี log เลย?&lt;&#x2F;p&gt;
&lt;p&gt;หรือถ้าใครมีเทคนิค build image ให้บางเฉียบแบบไม่ต้องเอา &lt;code&gt;node_modules&lt;&#x2F;code&gt; ติดมาด้วย — มาแชร์กันได้เลยครับ&lt;&#x2F;p&gt;
&lt;p&gt;จบโพสต์นี้แบบงง ๆ กับ CPU instruction set ไปก่อน
ไว้เจอกันใหม่ในตอน “bundle ให้จบ แล้วเหลือแค่ของจำเป็น” เร็ว ๆ นี้ครับ!&lt;&#x2F;p&gt;
&lt;p&gt;(ขอบคุณที่อ่านมาถึงตรงนี้นะ :D)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ลอง EasyOCR ภาษาไทย และเล่น uv ครั้งแรกในโปรเจกต์ OCR แบบ Python สมัยใหม่</title>
		<published>2025-05-16T00:00:00+00:00</published>
		<updated>2025-05-16T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/thai-ocr-easyocr-uv-python/" type="text/html"/>
		<id>https://thadaw.com/posts/thai-ocr-easyocr-uv-python/</id>
		<content type="html">&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;thai-ocr-easyocr-uv-python&#x2F;cover.jpg&quot; alt=&quot;cover&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;TL;DR&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;p&gt;ภาษาไทย OCR ยังไม่สมบูรณ์แบบ แต่ก็พอใช้ได้ในระดับฟรี เอาไปใช้ร่วมกับ GPT ช่วยปรับแก้ได้
Github Code: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;thai-ocr-with-easyocr&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;thai-ocr-with-easyocr&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ช่วงนี้มีโจทย์น่าสนุกจากฝั่งงาน Dev ให้ช่วย Proof of Concept ระบบ OCR สำหรับเอกสารภาษาไทย&lt;br &#x2F;&gt;
ก็เลยได้โอกาสลองของใหม่ 2 อย่างพร้อมกัน&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ลอง EasyOCR&lt;&#x2F;strong&gt; — ว่ามันอ่านภาษาไทยได้แค่ไหนในโลกจริง&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ลอง &lt;code&gt;uv&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; — เครื่องมือจัดการ Python project แบบ modern ที่มาแทน pip, venv, pip-tools ในตัวเดียว&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;erimcchaakocchthyngaay-aan-pdf-phaasaaaithy&quot;&gt;เริ่มจากโจทย์ง่าย ๆ: อ่าน PDF ภาษาไทย&lt;a class=&quot;zola-anchor&quot; href=&quot;#erimcchaakocchthyngaay-aan-pdf-phaasaaaithy&quot; aria-label=&quot;Anchor link for: erimcchaakocchthyngaay-aan-pdf-phaasaaaithy&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ใน POC รอบนี้ เราต้องอ่านไฟล์ PDF (ที่เป็น scanned document) แล้วแปลงเป็นข้อความ&lt;br &#x2F;&gt;
คำถามในหัวคือ… “OCR ภาษาไทยปี 2025 มันพอไหวมั้ยนะ?”&lt;&#x2F;p&gt;
&lt;p&gt;เลยลอง setup เบื้องต้นแบบเร็ว ๆ:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ใช้ &lt;code&gt;pdf2image&lt;&#x2F;code&gt; แปลง PDF → Image&lt;&#x2F;li&gt;
&lt;li&gt;ใช้ &lt;code&gt;easyocr&lt;&#x2F;code&gt; รองรับภาษา &lt;code&gt;[&#x27;th&#x27;, &#x27;en&#x27;]&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;บันทึกผลลัพธ์ลงไฟล์ text&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ผลลัพธ์ที่ได้ &lt;strong&gt;&quot;พอใช้ได้ในระดับ OCR ฟรี&quot;&lt;&#x2F;strong&gt; — ไม่เป๊ะทุกคำ แต่ถ้าเอกสารคม ๆ สะอาด ๆ ก็อ่านได้เยอะอยู่นะ
โดยเฉพาะตัวอักษรพิมพ์ดีด&#x2F;เอกสารราชการที่พิมพ์ตรง ๆ (ไม่ใช่สแกนเอกสารที่ซีดหรือเบี้ยว)&lt;&#x2F;p&gt;
&lt;p&gt;แต่ก็เอาไปใช้งานจริงไม่ได้เท่าไหร่นัก เลยเอาไปใช้ GPT ช่วยปรับแก้ให้เป็นข้อความที่อ่านง่ายขึ้น&lt;br &#x2F;&gt;
(ซึ่งก็ทำได้ดีในระดับนึง แต่ก็ยังมีข้อผิดพลาดอยู่บ้าง)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aelwkl-ngaich-uv-duukhrangaerk&quot;&gt;แล้วก็ลองใช้ &lt;code&gt;uv&lt;&#x2F;code&gt; ดูครั้งแรก...&lt;a class=&quot;zola-anchor&quot; href=&quot;#aelwkl-ngaich-uv-duukhrangaerk&quot; aria-label=&quot;Anchor link for: aelwkl-ngaich-uv-duukhrangaerk&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;โอ้โห รู้สึกเลยว่า Python มัน modern ขึ้น!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ปกติถ้าจะเริ่มโปรเจกต์ Python เราต้องตั้ง venv, สร้าง requirements.txt, ลง pip, ทำ pip freeze, จัด lockfile — เยอะเวอร์
แต่ &lt;code&gt;uv&lt;&#x2F;code&gt; ทำให้ทุกอย่างง่ายเหลือแค่คำสั่งเดียว:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;pip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; install easyocr pdf2image&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;pip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; freeze &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; requirements.txt&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;หรือถ้าจะจัดเต็มแบบ modern dev:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;uv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; init&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;uv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; add easyocr pdf2image&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;uv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sync&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;นอกจากจะเร็วกว่า pip เยอะมาก (เพราะเขียนด้วย Rust) ยังรวมระบบ lockfile แบบเดียวกับ &lt;code&gt;bun&lt;&#x2F;code&gt;, &lt;code&gt;pnpm&lt;&#x2F;code&gt; ไว้ด้วยเลย
แถมใช้แทน &lt;code&gt;virtualenv&lt;&#x2F;code&gt; ได้เลยด้วย 🎉&lt;&#x2F;p&gt;
&lt;h2 id=&quot;singthiiaidkhidcchaakkaarl-ngkh-ng&quot;&gt;สิ่งที่ได้คิดจากการลองของ&lt;a class=&quot;zola-anchor&quot; href=&quot;#singthiiaidkhidcchaakkaarl-ngkh-ng&quot; aria-label=&quot;Anchor link for: singthiiaidkhidcchaakkaarl-ngkh-ng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;บางทีการกลับมาลอง tools ใหม่ ๆ มันทำให้เรา “รู้สึกสนุก” กับ Python ขึ้นอีกครั้ง&lt;&#x2F;li&gt;
&lt;li&gt;OCR ภาษาไทยยังไม่สมบูรณ์แบบ แต่ก็พอจะเอาไปใช้ในงานจริงได้ ถ้ารู้ว่าจุดแข็ง-จุดอ่อนมันอยู่ตรงไหน&lt;&#x2F;li&gt;
&lt;li&gt;เครื่องมือดี ๆ อย่าง &lt;code&gt;uv&lt;&#x2F;code&gt; ทำให้ Python ecosystem ดู “ทันสมัย” ขึ้นมาก โดยเฉพาะกับคนที่ชอบ style แบบ TypeScript &#x2F; Bun&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;แล้วพบกันใหม่ สวัสดีครับ&lt;&#x2F;p&gt;
&lt;p&gt;ตัวอย่างโค้ดทั้งหมดอยู่ที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;thai-ocr-with-easyocr&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;thai-ocr-with-easyocr&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ตั้งค่าความปลอดภัยด้วย VPN with Tailscale และตั้งค่า Kubectl context ฉบับ Homelab EP. 2</title>
		<published>2025-05-13T00:00:00+00:00</published>
		<updated>2025-05-13T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/homelab-vpn-tailscale-kubectl-ep2/" type="text/html"/>
		<id>https://thadaw.com/posts/homelab-vpn-tailscale-kubectl-ep2/</id>
		<content type="html">&lt;p&gt;ช่วงนี้ผมเริ่มกลับมาเล่น Homelab ใหม่อีกครั้งหลังจากที่ปล่อยให้เครื่อง Ubuntu Server วางฝุ่นมานานสองปี ตอนแรกว่าจะเอาไว้เล่นเกม แต่มันก็ไม่ได้ใช้สักที เลยตัดสินใจเปลี่ยนมาใช้ทำ Homelab แทน&lt;&#x2F;p&gt;
&lt;p&gt;ใน &lt;strong&gt;EP.1&lt;&#x2F;strong&gt; ผมลง RKE2 (Kubernetes) บนเครื่อง Ubuntu Server เรียบร้อยแล้ว และสามารถ &lt;code&gt;kubectl&lt;&#x2F;code&gt; ได้จากในเครื่องเดียวกัน&lt;&#x2F;p&gt;
&lt;p&gt;แต่… ปัญหาคือผมอยากเข้าถึง cluster ได้ &lt;strong&gt;จากข้างนอกบ้าน&lt;&#x2F;strong&gt; บ้าง เช่น ผ่านโน้ตบุ๊กหรือมือถือเวลาอยู่นอกบ้าน หรือใช้ hotspot 5G เชื่อมต่อ ทำให้ต้องมีระบบ network ที่ปลอดภัยและเชื่อมต่อกลับบ้านได้&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;EP.2 นี้เลยจะพาไป:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ติดตั้ง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;tailscale.com&#x2F;&quot;&gt;Tailscale&lt;&#x2F;a&gt; เพื่อเชื่อมต่อเครื่องทุกตัวให้อยู่ใน network เดียวกันแบบ private VPN&lt;&#x2F;li&gt;
&lt;li&gt;ตั้งค่า &lt;code&gt;kubectl&lt;&#x2F;code&gt; ให้เชื่อมกับ K8s cluster ผ่านชื่อ domain ของ Tailscale (magicDNS)&lt;&#x2F;li&gt;
&lt;li&gt;แก้ปัญหา TLS certificate ที่ไม่ตรงชื่อ domain&lt;&#x2F;li&gt;
&lt;li&gt;และสรุปความเข้าใจเรื่อง token-based กับ cert-based auth ใน Kubernetes แบบง่าย ๆ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ทั้งหมดนี้จะเล่าตามสิ่งที่ผมเจอจริง และวิธีที่ผมใช้แก้แบบค่อย ๆ ทำ พร้อมจุดพลาดที่ควรระวังครับ&lt;&#x2F;p&gt;
&lt;p&gt;ไปลุยกันเลย 🔧&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thamaimthuengeluue-kaich-tailscale&quot;&gt;ทำไมถึงเลือกใช้ Tailscale?&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaimthuengeluue-kaich-tailscale&quot; aria-label=&quot;Anchor link for: thamaimthuengeluue-kaich-tailscale&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;พอเริ่มทำ Homelab จริงจัง สิ่งที่อยากได้มากที่สุดคือ “ความสะดวกในการเข้าถึงเครื่องที่บ้านจากที่ไหนก็ได้”
ไม่ว่าจะนั่งอยู่คาเฟ่ ใช้ 5G hotspot หรือเปิดเครื่องจากต่างจังหวัด ก็อยากจะ &lt;code&gt;ssh&lt;&#x2F;code&gt; หรือ &lt;code&gt;kubectl&lt;&#x2F;code&gt; เข้าบ้านได้เหมือนนั่งอยู่ใน network เดียวกัน&lt;&#x2F;p&gt;
&lt;p&gt;แน่นอนว่าเราสามารถ forward port จาก router ก็ได้ หรือใช้ Dynamic DNS ก็ได้
แต่ทั้งสองวิธีนั้นมีความยุ่งยากหลายอย่าง เช่น ต้องตั้งค่า firewall เอง, เสี่ยงโดน scan จากภายนอก, และยังต้องจัดการกับ IP เปลี่ยนบ่อย ๆ ด้วย&lt;&#x2F;p&gt;
&lt;p&gt;ผมเลยมองหา solution ที่ทำให้:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ทุกเครื่องเชื่อมต่อกันได้เหมือนอยู่ใน network เดียวกัน&lt;&#x2F;li&gt;
&lt;li&gt;ไม่ต้องเปิดพอร์ตหรือยุ่งกับ router&lt;&#x2F;li&gt;
&lt;li&gt;มีระบบ identity, auth และ DNS มาให้ครบ&lt;&#x2F;li&gt;
&lt;li&gt;และที่สำคัญ... &lt;strong&gt;ตั้งค่าง่าย ไม่ต้อง config เยอะ&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;สุดท้ายก็มาเจอกับ &lt;strong&gt;Tailscale&lt;&#x2F;strong&gt; ที่ตอบโจทย์เกือบทุกข้อแบบไม่ต้องตั้งค่าอะไรเยอะเลย
แค่ login ก็ใช้งานได้ทันที&lt;&#x2F;p&gt;
&lt;p&gt;จากตรงนี้แหละครับ ที่ทำให้ผมตัดสินใจจะติดตั้ง Tailscale บน Ubuntu Server ที่เป็นเครื่องหลักใน Homelab&lt;&#x2F;p&gt;
&lt;p&gt;ไปดูกันว่าเราจะติดตั้งยังไง และเชื่อมเครื่องต่าง ๆ เข้า network เดียวกันได้ยังไงครับ 🛠️&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tidtang-tailscale-bn-ubuntu-server&quot;&gt;ติดตั้ง Tailscale บน Ubuntu Server&lt;a class=&quot;zola-anchor&quot; href=&quot;#tidtang-tailscale-bn-ubuntu-server&quot; aria-label=&quot;Anchor link for: tidtang-tailscale-bn-ubuntu-server&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จะเห็นว่าผมลง App ของ Tailscale ไว้บน Mac Mini เรียบร้อยแล้ว มันขึ้นมาว่ามี device เชื่อมอยู่แค่เครื่องเดียว
ยังไม่ได้ลงฝั่ง Ubuntu Server เลย ซึ่งเป็นเครื่องหลักที่รัน RKE2 อยู่&lt;&#x2F;p&gt;
&lt;p&gt;วันนี้เราจะมาลง Tailscale บน Ubuntu Server กันครับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;homelab-vpn-tailscale-kubectl-ep2&#x2F;tailscale-setup-guide.png&quot; alt=&quot;Tailscale setup screen showing Mac Mini as the first connected device and prompting to add a second device, such as Ubuntu Server.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;เริ่มจากคำสั่งติดตั้งตามที่หน้าเว็บเค้าแนะนำ:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;curl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;fsSL&lt;&#x2F;span&gt; https:&#x2F;&#x2F;tailscale.com&#x2F;install.sh&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;หลังจากนั้นมันจะขึ้นข้อความแนะนำว่าให้เรา &lt;code&gt;sudo tailscale up&lt;&#x2F;code&gt; เพื่อเริ่มใช้งาน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Installation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; complete! Log in to start using Tailscale by running:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; tailscale up&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เมื่อรันคำสั่งนี้ มันจะให้ลิงก์มาให้เราไปเปิดใน Browser เพื่อ login ด้วยบัญชี Google หรือ Microsoft ที่เราใช้กับ Tailscale&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo tailscale up&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;To&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; authenticate, visit:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;https:&#x2F;&#x2F;login.tailscale.com&#x2F;a&#x2F;xxxxxxx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เปิดลิงก์นั้นใน browser แล้วกด login ให้เสร็จ จากนั้น… พร้อมแล้วครับ!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;homelab-vpn-tailscale-kubectl-ep2&#x2F;tailscale-connected.png&quot; alt=&quot;Tailscale setup complete screen showing successful connection between two devices: thadas-mac-mini and thadawth.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;พอเสร็จแล้วเราจะเห็นว่าเครื่อง Mac กับ Ubuntu Server จะถูกเชื่อมอยู่ในเครือข่ายเดียวกันเรียบร้อย
ที่น่าทึ่งคือ เราสามารถ access กันผ่านชื่อ domain ได้เลยด้วย โดยไม่ต้องจำ IP อีกต่อไป&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ssh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; thadawth.tail1234da.ts.net&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;my_home_lab&#x2F;id_rsa&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ชื่อแบบนี้มาจาก magicDNS ของ Tailscale ซึ่งมันจะผูก domain ให้ device แต่ละตัวอัตโนมัติ โดย domain ทั้งหมดจะอยู่ภายใต้ tailnet name ของเรา&lt;&#x2F;p&gt;
&lt;p&gt;ชื่อ tailnet จะหน้าตาประมาณนี้:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;xxxx.ts.net
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ซึ่งตอนสมัครเค้าจะสุ่มมาให้เรา แต่เราสามารถเข้าไปเปลี่ยนชื่อได้ภายหลังที่หน้า admin console ของ Tailscale&lt;&#x2F;p&gt;
&lt;p&gt;และทุกเครื่องที่เชื่อมต่อจะได้ทั้ง IP address (ของ Tailscale) และ domain name ส่วนตัว
เช่น&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mac-mini.tail1234da.ts.net
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ubuntu-server.tail1234da.ts.net
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ผมก็สามารถ ssh ข้ามไปยังเครื่อง ubuntu-server ได้จากที่ไหนก็ได้ผ่าน domain นี้เลย&lt;&#x2F;p&gt;
&lt;p&gt;หลังจากเชื่อมกันได้แล้ว อีกฟีเจอร์หนึ่งที่แนะนำให้เปิดคือ &lt;strong&gt;HTTPS support&lt;&#x2F;strong&gt; ของ Tailscale
จะช่วยให้ domain ที่เราจะเรียก (เช่น &lt;code&gt;https:&#x2F;&#x2F;my-node.tail1234da.ts.net&lt;&#x2F;code&gt;) ใช้ TLS ได้แบบ auto-verified จาก browser ทั่วไป&lt;&#x2F;p&gt;
&lt;p&gt;เปิดได้ง่าย ๆ ที่หน้า DNS ของ admin console:
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;login.tailscale.com&#x2F;admin&#x2F;dns&quot;&gt;https:&#x2F;&#x2F;login.tailscale.com&#x2F;admin&#x2F;dns&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;homelab-vpn-tailscale-kubectl-ep2&#x2F;tailscale-enable-https.png&quot; alt=&quot;Tailscale UI that show how to enable HTTPS&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ต่อไปเราจะเริ่มตั้งค่า &lt;code&gt;kubectl&lt;&#x2F;code&gt; เพื่อเชื่อมกับ RKE2 cluster ผ่าน DNS ตัวนี้กันครับ และดูว่าเราจะเจอ TLS error แบบไหนบ้าง แล้วแก้ยังไงให้เชื่อมต่อได้จากนอกบ้านแบบปลอดภัย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tangkhaa-kubectl-aihaich-dns-kh-ng-tailscale-echuue-maipthii-cluster&quot;&gt;ตั้งค่า &lt;code&gt;kubectl&lt;&#x2F;code&gt; ให้ใช้ DNS ของ Tailscale เชื่อมไปที่ Cluster&lt;a class=&quot;zola-anchor&quot; href=&quot;#tangkhaa-kubectl-aihaich-dns-kh-ng-tailscale-echuue-maipthii-cluster&quot; aria-label=&quot;Anchor link for: tangkhaa-kubectl-aihaich-dns-kh-ng-tailscale-echuue-maipthii-cluster&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลังจากที่เราเชื่อมเครื่อง Mac กับ Ubuntu Server เข้าด้วยกันผ่าน Tailscale ได้แล้ว
ผมก็อยากจะ &lt;code&gt;kubectl&lt;&#x2F;code&gt; เข้าไปยัง RKE2 cluster จากเครื่อง Mac ผ่าน domain ของ Tailscale เลย&lt;&#x2F;p&gt;
&lt;p&gt;เครื่อง Ubuntu Server ของผมรัน RKE2 อยู่ที่:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;https:&#x2F;&#x2F;192.168.1.107:6443
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แต่พอเรามี Tailscale แล้ว เราสามารถเปลี่ยนไปใช้ชื่อ domain ได้เลย เช่น:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;https:&#x2F;&#x2F;thadawth.tail1234da.ts.net:6443
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ซึ่งเป็น magicDNS ของเครื่อง Ubuntu Server ที่ได้จาก Tailscale&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ephim-context-aihmekhaaaipain-kubeconfig&quot;&gt;เพิ่ม context ใหม่เข้าไปใน kubeconfig&lt;a class=&quot;zola-anchor&quot; href=&quot;#ephim-context-aihmekhaaaipain-kubeconfig&quot; aria-label=&quot;Anchor link for: ephim-context-aihmekhaaaipain-kubeconfig&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ผมลองสร้าง context ใหม่ใน &lt;code&gt;~&#x2F;.kube&#x2F;config&lt;&#x2F;code&gt; แบบนี้ครับ:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;v1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;clusters&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;cluster&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;certificate-authority-data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;xxx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;https:&#x2F;&#x2F;192.168.1.107:6443&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;my_homelab-cluster&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;cluster&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;certificate-authority-data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;xxx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;https:&#x2F;&#x2F;thadawth.tail1234da.ts.net:6443&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;my_homelab-cluster_tailscale&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นลองรันคำสั่ง:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; config use-context my_homelab-cluster_tailscale&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; get pods&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ผลลัพธ์คือ...&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;E0512 17:44:46.732328   34569 memcache.go:265] &amp;quot;Unhandled Error&amp;quot; err=&amp;quot;couldn&amp;#39;t get current server API group list: Get \&amp;quot;https:&#x2F;&#x2F;thadawth.tail1234da.ts.net:6443&#x2F;api?timeout=32s\&amp;quot;: tls: failed to verify certificate: x509: certificate is valid for ..., not thadawth.tail1234da.ts.net&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;อ้าว... ทำไมเป็นแบบนี้?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;payhaakhuue-tls-certificate-aimr-ngrabchuue-tailscale-dns&quot;&gt;ปัญหาคือ TLS Certificate ไม่รองรับชื่อ Tailscale DNS&lt;a class=&quot;zola-anchor&quot; href=&quot;#payhaakhuue-tls-certificate-aimr-ngrabchuue-tailscale-dns&quot; aria-label=&quot;Anchor link for: payhaakhuue-tls-certificate-aimr-ngrabchuue-tailscale-dns&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ผมเลยลอง inspect ตัว cert ที่ Kube API Server ใช้อยู่ ด้วย &lt;code&gt;openssl&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;openssl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; s_client&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;connect&lt;&#x2F;span&gt; 127.0.0.1:6443&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;showcerts&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&#x2F;dev&#x2F;null &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-file-descriptor z-shell&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&#x2F;dev&#x2F;null &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;&#x2F;span&gt;  &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;openssl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; x509&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;noout&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;text&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;grep&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;A1&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Subject Alternative Name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ผลที่ได้คือ:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; class=&quot;language-text z-code&quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;X509v3 Subject Alternative Name:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    DNS:kubernetes.default.svc.cluster.local, DNS:localhost, DNS:thadawth,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    IP Address:127.0.0.1, IP Address:192.168.1.107, ...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากตรงนี้เราจะเห็นว่า &lt;strong&gt;ไม่มีชื่อ &lt;code&gt;thadawth.tail1234da.ts.net&lt;&#x2F;code&gt; อยู่ใน SAN&lt;&#x2F;strong&gt; ของ cert เลย
ซึ่งหมายความว่า ถึงแม้จะชี้ DNS มาถูกต้องแล้ว &lt;code&gt;kubectl&lt;&#x2F;code&gt; ก็จะไม่ยอมเชื่อถือ server เพราะ TLS ไม่ match&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thamaih-kube-api-server-r-ngrabchuue-dns-kh-ng-tailscale&quot;&gt;ทำให้ Kube API Server รองรับชื่อ DNS ของ Tailscale&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaih-kube-api-server-r-ngrabchuue-dns-kh-ng-tailscale&quot; aria-label=&quot;Anchor link for: thamaih-kube-api-server-r-ngrabchuue-dns-kh-ng-tailscale&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จากตอนที่แล้วเรารู้แล้วว่า &lt;code&gt;kubectl&lt;&#x2F;code&gt; เชื่อมผ่าน DNS ของ Tailscale ไม่ได้ เพราะ &lt;strong&gt;cert ไม่ครอบคลุมชื่อที่ใช้&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ทางแก้คือ…
เราต้อง &lt;strong&gt;เพิ่ม DNS ของ Tailscale (&lt;code&gt;thadawth.tail1234da.ts.net&lt;&#x2F;code&gt;) เข้าไปใน TLS certificate ของ RKE2&lt;&#x2F;strong&gt;
ซึ่งเราทำได้โดยการตั้งค่าในไฟล์ config แล้วให้ RKE2 regenerate cert ใหม่ให้ครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-aekaifl-config-yaml-kh-ng-rke2&quot;&gt;1. แก้ไฟล์ config.yaml ของ RKE2&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-aekaifl-config-yaml-kh-ng-rke2&quot; aria-label=&quot;Anchor link for: 1-aekaifl-config-yaml-kh-ng-rke2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;RKE2 จะอ่านค่าจากไฟล์นี้:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;etc&#x2F;rancher&#x2F;rke2&#x2F;config.yaml
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถ้าไฟล์นี้ยังไม่มี ให้เราสร้างใหม่ได้เลย:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkdir&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;p&lt;&#x2F;span&gt; &#x2F;etc&#x2F;rancher&#x2F;rke2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; nano &#x2F;etc&#x2F;rancher&#x2F;rke2&#x2F;config.yaml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แล้วใส่ค่าแบบนี้ (เพิ่ม DNS ที่เราต้องการลงไป):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;tls-san&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;192.168.1.107&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;thadawth.tail1234da.ts.net&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;บรรทัดแรกคือ IP เดิมที่มีอยู่แล้ว บรรทัดที่สองคือ DNS จาก Tailscale ที่เราต้องการให้ cert รองรับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-lb-cert-ekaa-ephuue-aih-rke2-sraangaihm&quot;&gt;2. ลบ cert เก่า (เพื่อให้ RKE2 สร้างใหม่)&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-lb-cert-ekaa-ephuue-aih-rke2-sraangaihm&quot; aria-label=&quot;Anchor link for: 2-lb-cert-ekaa-ephuue-aih-rke2-sraangaihm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; systemctl stop rke2-server&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; rm &#x2F;var&#x2F;lib&#x2F;rancher&#x2F;rke2&#x2F;server&#x2F;tls&#x2F;serving-kube-apiserver.crt&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; rm &#x2F;var&#x2F;lib&#x2F;rancher&#x2F;rke2&#x2F;server&#x2F;tls&#x2F;serving-kube-apiserver.key&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;⚠️ ระวัง:&lt;&#x2F;strong&gt; อย่าลบไฟล์ &lt;code&gt;server-ca.key&lt;&#x2F;code&gt; เด็ดขาดนะครับ อันนั้นคือ root CA ของระบบ ถ้าหาย = cluster พัง&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-start-rke2-aihm-ephuue-aihmansraang-cert-aihmthiirwm-dns-thiieraat-ngkaar&quot;&gt;3. Start RKE2 ใหม่ เพื่อให้มันสร้าง cert ใหม่ที่รวม DNS ที่เราต้องการ&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-start-rke2-aihm-ephuue-aihmansraang-cert-aihmthiirwm-dns-thiieraat-ngkaar&quot; aria-label=&quot;Anchor link for: 3-start-rke2-aihm-ephuue-aihmansraang-cert-aihmthiirwm-dns-thiieraat-ngkaar&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; systemctl start rke2-server&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นรอให้ cluster กลับมาพร้อม (&lt;code&gt;kubectl get nodes&lt;&#x2F;code&gt; ต้องใช้ได้จากเครื่อง server)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4-trwcchs-b-cert-aihm&quot;&gt;4. ตรวจสอบ cert ใหม่&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-trwcchs-b-cert-aihm&quot; aria-label=&quot;Anchor link for: 4-trwcchs-b-cert-aihm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ลองใช้ &lt;code&gt;openssl&lt;&#x2F;code&gt; ดูอีกทีว่า DNS ของเราถูกเพิ่มเข้าไปแล้วจริงไหม:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;openssl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; s_client&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;connect&lt;&#x2F;span&gt; 127.0.0.1:6443&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;showcerts&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&#x2F;dev&#x2F;null &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-file-descriptor z-shell&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&#x2F;dev&#x2F;null &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;&#x2F;span&gt;  &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;openssl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; x509&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;noout&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;text&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;grep&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;A1&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Subject Alternative Name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ตอนนี้น่าจะเห็น:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;DNS:thadawth.tail1234da.ts.net
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;โผล่มาแล้วเรียบร้อย 🎉&lt;&#x2F;p&gt;
&lt;h3 id=&quot;echuue-mt-cchaakekhruue-ng-uuenphaan-dns-yangaimaid&quot;&gt;เชื่อมต่อจากเครื่องอื่นผ่าน DNS... ยังไม่ได้&lt;a class=&quot;zola-anchor&quot; href=&quot;#echuue-mt-cchaakekhruue-ng-uuenphaan-dns-yangaimaid&quot; aria-label=&quot;Anchor link for: echuue-mt-cchaakekhruue-ng-uuenphaan-dns-yangaimaid&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;หลังจากที่เราเพิ่ม &lt;code&gt;thadawth.tail1234da.ts.net&lt;&#x2F;code&gt; เข้าไปใน SAN ของ cert แล้ว
ผมก็กลับมาที่เครื่อง Mac แล้วลองรัน &lt;code&gt;kubectl get nodes&lt;&#x2F;code&gt; ผ่าน context ที่ชี้ไปยัง DNS นี้&lt;&#x2F;p&gt;
&lt;p&gt;ผลคือ... ยังไม่ได้ครับ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Unable&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; to connect to the server: x509: certificate signed by unknown authority&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถึงแม้ cert จะรองรับชื่อ DNS แล้ว แต่ฝั่ง client (เครื่อง Mac) ยังไม่สามารถ “เชื่อถือ” cert ได้อยู่ดี
เพราะใน &lt;code&gt;kubeconfig.yaml&lt;&#x2F;code&gt; ที่เราสร้างไว้ ยังใส่ &lt;code&gt;certificate-authority-data:&lt;&#x2F;code&gt; ไม่ถูกตัวนั่นเอง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aich-certificate-authority-data-thiithuukt-ng-ephuue-aihechuue-mt-phaan-dns-aidcchring&quot;&gt;ใช้ &lt;code&gt;certificate-authority-data&lt;&#x2F;code&gt; ที่ถูกต้อง เพื่อให้เชื่อมต่อผ่าน DNS ได้จริง&lt;a class=&quot;zola-anchor&quot; href=&quot;#aich-certificate-authority-data-thiithuukt-ng-ephuue-aihechuue-mt-phaan-dns-aidcchring&quot; aria-label=&quot;Anchor link for: aich-certificate-authority-data-thiithuukt-ng-ephuue-aihechuue-mt-phaan-dns-aidcchring&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ปัญหาจริง ๆ ไม่ได้อยู่ที่ cert ฝั่ง server แล้ว แต่เกิดจาก &lt;code&gt;certificate-authority-data:&lt;&#x2F;code&gt; ฝั่ง client
ใน &lt;code&gt;kubeconfig.yaml&lt;&#x2F;code&gt; เราต้องใส่ cert ที่ตรงกับ CA ที่ใช้ sign cert ฝั่ง server จริง ๆ&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งในกรณีของ RKE2 เราใช้ cert เดียวกับที่ Kube API Server ใช้รับการเชื่อมต่ออยู่แล้ว
คือไฟล์ &lt;code&gt;serving-kube-apiserver.crt&lt;&#x2F;code&gt; ที่เราพูดถึงในขั้นตอนก่อนหน้า&lt;&#x2F;p&gt;
&lt;p&gt;เราสามารถใช้คำสั่งนี้เพื่อ base64 cert ออกมาได้:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; cat &#x2F;var&#x2F;lib&#x2F;rancher&#x2F;rke2&#x2F;server&#x2F;tls&#x2F;serving-kube-apiserver.crt&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;base64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;tr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;d&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;\n&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นเอาค่านี้ไปใส่ใน &lt;code&gt;kubeconfig.yaml&lt;&#x2F;code&gt; ตรง &lt;code&gt;certificate-authority-data:&lt;&#x2F;code&gt;
แล้วลอง &lt;code&gt;kubectl get nodes&lt;&#x2F;code&gt; จากเครื่องนอกบ้านอีกครั้ง&lt;&#x2F;p&gt;
&lt;p&gt;ครั้งนี้เชื่อมต่อได้เรียบร้อย
และระบบก็เชื่อถือ cert ได้อย่างถูกต้องปลอดภัย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;optional-sraang-account-aihmsamhrabkaarechuue-mt-cchaakekhruue-ngn-kbaan-aebb-token&quot;&gt;(Optional) สร้าง Account ใหม่สำหรับการเชื่อมต่อจากเครื่องนอกบ้าน แบบ Token&lt;a class=&quot;zola-anchor&quot; href=&quot;#optional-sraang-account-aihmsamhrabkaarechuue-mt-cchaakekhruue-ngn-kbaan-aebb-token&quot; aria-label=&quot;Anchor link for: optional-sraang-account-aihmsamhrabkaarechuue-mt-cchaakekhruue-ngn-kbaan-aebb-token&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ถ้าเราไม่อยากใช้ cert เดิมที่ RKE2 สร้างให้ตั้งแต่ตอนติดตั้ง
(เพราะมัน embed cert+key แบบ root user ไว้ในไฟล์ &lt;code&gt;rke2.yaml&lt;&#x2F;code&gt;)
หรือเราอยากแยก context สำหรับใช้งานจากเครื่องอื่น โดยเฉพาะ...&lt;&#x2F;p&gt;
&lt;p&gt;เราสามารถสร้าง ServiceAccount ใหม่ แล้ว generate &lt;code&gt;kubeconfig.yaml&lt;&#x2F;code&gt; สำหรับ user นั้นได้เลยครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-sraang-serviceaccount-aihm&quot;&gt;1. สร้าง ServiceAccount ใหม่&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-sraang-serviceaccount-aihm&quot; aria-label=&quot;Anchor link for: 1-sraang-serviceaccount-aihm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;สมมติผมจะสร้างชื่อว่า &lt;code&gt;remote-admin&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create serviceaccount remote-admin&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;n&lt;&#x2F;span&gt; default&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;2-aihsiththiaebb-admin-hruue-cchacchamkad-namespace-kaid&quot;&gt;2. ให้สิทธิ์แบบ admin (หรือจะจำกัด namespace ก็ได้)&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-aihsiththiaebb-admin-hruue-cchacchamkad-namespace-kaid&quot; aria-label=&quot;Anchor link for: 2-aihsiththiaebb-admin-hruue-cchacchamkad-namespace-kaid&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ถ้าอยากให้ใช้ได้เหมือน user หลัก:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create clusterrolebinding remote-admin-binding &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;  --&lt;&#x2F;span&gt;clusterrole&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;cluster-admin &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;  --&lt;&#x2F;span&gt;serviceaccount&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;default:remote-admin&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;3-sraang-token-aebb-short-lived-kubernetes-1-24&quot;&gt;3. สร้าง token แบบ short-lived (Kubernetes &amp;gt;= 1.24)&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-sraang-token-aebb-short-lived-kubernetes-1-24&quot; aria-label=&quot;Anchor link for: 3-sraang-token-aebb-short-lived-kubernetes-1-24&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create token remote-admin&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;n&lt;&#x2F;span&gt; default&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;มันจะ print token ออกมาทาง stdout → เก็บไว้ก่อน&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4-dueng-ca-crt-thiiaichsamhrab-certificate-authority-data&quot;&gt;4. ดึง &lt;code&gt;ca.crt&lt;&#x2F;code&gt; ที่ใช้สำหรับ certificate-authority-data&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-dueng-ca-crt-thiiaichsamhrab-certificate-authority-data&quot; aria-label=&quot;Anchor link for: 4-dueng-ca-crt-thiiaichsamhrab-certificate-authority-data&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เราเคยได้ base64 cert ที่ถูกต้องไว้แล้วจากไฟล์นี้:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; cat &#x2F;var&#x2F;lib&#x2F;rancher&#x2F;rke2&#x2F;server&#x2F;tls&#x2F;serving-kube-apiserver.crt&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;base64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;tr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;d&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;\n&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;5-sraangaifl-kubeconfig-yaml&quot;&gt;5. สร้างไฟล์ &lt;code&gt;kubeconfig.yaml&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#5-sraangaifl-kubeconfig-yaml&quot; aria-label=&quot;Anchor link for: 5-sraangaifl-kubeconfig-yaml&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;v1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;kind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Config&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;clusters&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;my-homelab_remote&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;cluster&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;https:&#x2F;&#x2F;thadawth.tail1234da.ts.net:6443&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;certificate-authority-data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&amp;lt;ใส่ base64 CA ที่ได้มาข้างบน&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;users&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;remote-admin&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&amp;lt;ใส่ token ที่ create มาข้างบน&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;contexts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;my-homelab_remote-context&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;cluster&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;my-homelab_remote&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;remote-admin&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;current-context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;my-homelab_remote-context&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;6-aichngaancchaakekhruue-ng-uuen-scp-aela-merge-context&quot;&gt;6. ใช้งานจากเครื่องอื่น: scp และ merge context&lt;a class=&quot;zola-anchor&quot; href=&quot;#6-aichngaancchaakekhruue-ng-uuen-scp-aela-merge-context&quot; aria-label=&quot;Anchor link for: 6-aichngaancchaakekhruue-ng-uuen-scp-aela-merge-context&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;สมมติว่าเราอยู่ที่เครื่อง remote (เช่นเครื่อง Mac) แล้วต้องการเชื่อมต่อไปยัง Homelab ผ่าน Tailscale
เราจะทำตามขั้นตอนนี้:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;6-1-copy-kubeconfig-maacchaakekhruue-ng-homelab&quot;&gt;6.1 copy kubeconfig มาจากเครื่อง Homelab&lt;a class=&quot;zola-anchor&quot; href=&quot;#6-1-copy-kubeconfig-maacchaakekhruue-ng-homelab&quot; aria-label=&quot;Anchor link for: 6-1-copy-kubeconfig-maacchaakekhruue-ng-homelab&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;scp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;my_home_lab&#x2F;id_rsa &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;    thadawth@thadawth.tail1234da.ts.net:&#x2F;home&#x2F;thadawth&#x2F;scripts&#x2F;remote-kubeconfig.yaml &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;    .&#x2F;remote-kubeconfig.yaml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;6-2-merge-context-ekhaakab-kube-config-thiiaichngaan-yuu&quot;&gt;6.2 merge context เข้ากับ ~&#x2F;.kube&#x2F;config ที่ใช้งานอยู่&lt;a class=&quot;zola-anchor&quot; href=&quot;#6-2-merge-context-ekhaakab-kube-config-thiiaichngaan-yuu&quot; aria-label=&quot;Anchor link for: 6-2-merge-context-ekhaakab-kube-config-thiiaichngaan-yuu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;KUBECONFIG&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.kube&#x2F;config:.&#x2F;remote-kubeconfig.yaml&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; config view&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;flatten&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; merged-config.yaml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.kube&#x2F;config &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.kube&#x2F;config.backup.&lt;span class=&quot;z-meta z-group z-expansion z-command z-parens z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;date&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; +&lt;span class=&quot;z-meta z-group z-expansion z-job z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-job z-shell&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;Y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-job z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-job z-shell&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-job z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-job z-shell&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;-&lt;span class=&quot;z-meta z-group z-expansion z-job z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-job z-shell&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;H&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-job z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-job z-shell&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;M&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-job z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-job z-shell&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;S&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; merged-config.yaml &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.kube&#x2F;config&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นเช็กดูว่า context ใหม่เพิ่มเข้ามาหรือยัง:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; config get-contexts&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เราควรเห็นชื่อ context ที่ตั้งไว้ เช่น &lt;code&gt;my-homelab_remote-context&lt;&#x2F;code&gt;
จากนั้นก็สามารถสลับ context แล้วใช้งานได้ทันที:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; config use-context my-homelab_remote-context&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; get nodes&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แค่นี้เราก็สามารถ &lt;code&gt;kubectl&lt;&#x2F;code&gt; จากเครื่องข้างนอกเข้ามายัง cluster ที่บ้านได้แล้วครับ
ผ่าน domain ของ Tailscale แบบปลอดภัย และแยก context ได้ชัดเจน 🎯&lt;&#x2F;p&gt;
&lt;h2 id=&quot;token-vs-cert-based-auth-aairpl-dphaykwaakan&quot;&gt;Token vs Cert-based auth – อะไรปลอดภัยกว่ากัน?&lt;a class=&quot;zola-anchor&quot; href=&quot;#token-vs-cert-based-auth-aairpl-dphaykwaakan&quot; aria-label=&quot;Anchor link for: token-vs-cert-based-auth-aairpl-dphaykwaakan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ตอนที่ผมเริ่มตั้งค่าการเชื่อมต่อจากเครื่องนอกบ้าน สิ่งที่ต้องเจอแน่ ๆ คือคำถามนี้เลย
จะใช้ token ดีมั้ย หรือจะ generate cert-based user ดีกว่า?&lt;&#x2F;p&gt;
&lt;p&gt;ใน Kubernetes ทั้งสองวิธีนี้ถือว่าเป็น “ทางการ” ทั้งคู่
แต่พอใช้งานจริงจะมีลักษณะแตกต่างกันอยู่พอสมควร&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Token-based auth&lt;&#x2F;strong&gt; อย่างที่เราใช้กับ &lt;code&gt;kubectl create token&lt;&#x2F;code&gt; จะออก token มาเป็น string ยาว ๆ เอาไปใส่ใน kubeconfig ได้เลย
ข้อดีคือใช้ง่ายมาก ไม่ต้องสร้าง key-pair หรือ cert ใด ๆ
เหมาะกับ automation, bot, หรือเวลาต้องใช้ชั่วคราวใน script&lt;&#x2F;p&gt;
&lt;p&gt;แต่ข้อเสียคือ... ถ้า token นี้รั่ว ก็สามารถถูกนำไปใช้ได้ทันทีเหมือนรหัสผ่าน
และในกรณีที่เป็น static token มันมักจะไม่มีวันหมดอายุด้วย&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าจะปลอดภัยขึ้น ควรใช้ projected token หรือ short-lived token ที่ Kubernetes version ใหม่ ๆ รองรับ
(อันนี้แหละที่เราสร้างไว้ในตอนก่อนหน้า)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Cert-based auth&lt;&#x2F;strong&gt; จะใช้ public&#x2F;private keypair
ต้องมีการออก cert โดย CA ของ cluster (หรือ external CA) แล้วฝังลงใน kubeconfig
เวลาจะ revoke ก็ทำได้จากฝั่ง server โดยไม่ต้องไปลบไฟล์ token ที่ฝั่ง user&lt;&#x2F;p&gt;
&lt;p&gt;ข้อดีคือปลอดภัยสูง ใช้ TLS ระดับ x509 มาตรฐาน
และสามารถระบุตัวตนได้แบบละเอียด เช่น อ้างอิง username, group, หรือ cert fingerprint ได้เลย&lt;&#x2F;p&gt;
&lt;p&gt;ข้อเสียคือมันตั้งค่ายุ่งกว่า ถ้าไม่มีระบบจัดการ cert อัตโนมัติ
และถ้า private key รั่ว ก็ไม่ต่างอะไรกับ token ที่รั่วเช่นกัน&lt;&#x2F;p&gt;
&lt;h3 id=&quot;aelw-rke2-aich-aairepn-default&quot;&gt;แล้ว RKE2 ใช้อะไรเป็น default?&lt;a class=&quot;zola-anchor&quot; href=&quot;#aelw-rke2-aich-aairepn-default&quot; aria-label=&quot;Anchor link for: aelw-rke2-aich-aairepn-default&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;คำตอบคือ &lt;strong&gt;cert-based auth&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ตอนติดตั้ง RKE2 เสร็จ มันจะ generate cert ให้กับ user ชื่อ &lt;code&gt;kubernetes-admin&lt;&#x2F;code&gt; หรือบางกรณีก็เป็น &lt;code&gt;rke2-default&lt;&#x2F;code&gt;
พร้อมกับสร้าง kubeconfig ที่ฝัง &lt;code&gt;client-certificate-data&lt;&#x2F;code&gt; กับ &lt;code&gt;client-key-data&lt;&#x2F;code&gt; ไว้ในตัวเลย
เราสามารถเอาไฟล์นั้นไปใช้ได้ทันทีโดยไม่ต้องสร้างอะไรเพิ่ม&lt;&#x2F;p&gt;
&lt;p&gt;ผมคิดว่าเหตุผลที่ RKE2 เลือกใช้ cert เพราะมัน “ปลอดภัยโดยไม่ต้องพึ่ง external auth system”
และใช้งานง่ายใน context ของ Homelab หรือ air-gapped environment ที่ไม่ได้เชื่อมกับ Azure AD หรือ OIDC&lt;&#x2F;p&gt;
&lt;p&gt;สำหรับผมก็คือ&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ใช้ cert-based สำหรับผู้ใช้งานหลัก ที่ต้องเข้าควบคุม cluster&lt;&#x2F;li&gt;
&lt;li&gt;ใช้ token-based สำหรับ automation หรือการเชื่อมต่อเฉพาะกิจ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;srup-echuue-m-rke2-phaan-tailscale-aebbpl-dphay-chbab-homelab&quot;&gt;สรุป: เชื่อม RKE2 ผ่าน Tailscale แบบปลอดภัย ฉบับ Homelab&lt;a class=&quot;zola-anchor&quot; href=&quot;#srup-echuue-m-rke2-phaan-tailscale-aebbpl-dphay-chbab-homelab&quot; aria-label=&quot;Anchor link for: srup-echuue-m-rke2-phaan-tailscale-aebbpl-dphay-chbab-homelab&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลังจากลองปรับไปหลายรอบ ในที่สุดผมก็สามารถเชื่อม &lt;code&gt;kubectl&lt;&#x2F;code&gt; จากเครื่องอื่นเข้า RKE2 ที่บ้านผ่าน Tailscale ได้แบบปลอดภัยเต็มระบบ&lt;&#x2F;p&gt;
&lt;p&gt;สิ่งที่ดูเหมือนจะง่ายอย่างการ “แค่เปลี่ยนจาก local IP เป็น DNS” จริง ๆ แล้วต้องเข้าใจเรื่อง TLS, cert, SAN, และ auth อยู่พอสมควร
แต่พอเข้าใจแล้วก็ไม่ได้ยากอย่างที่คิดครับ&lt;&#x2F;p&gt;
&lt;p&gt;สิ่งที่ผมได้เรียนรู้จากรอบนี้คือ:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tailscale ช่วยให้ทุกเครื่องเชื่อมอยู่ใน network เดียวกันได้ง่ายมาก&lt;&#x2F;strong&gt; ไม่ต้องตั้งค่า router หรือ port forwarding อะไรเลย&lt;&#x2F;li&gt;
&lt;li&gt;แค่เปลี่ยนจาก local IP เป็น DNS ยังไม่พอ &lt;strong&gt;ต้อง regenerate cert ของ Kube API Server ให้รองรับชื่อ DNS ใหม่ด้วย&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ถ้า &lt;code&gt;certificate-authority-data&lt;&#x2F;code&gt; ไม่ตรงกับ CA ที่เซ็น cert จริง ๆ ก็จะเชื่อมไม่ได้ ถึงแม้ชื่อจะ match แล้วก็ตาม&lt;&#x2F;li&gt;
&lt;li&gt;การสร้าง &lt;code&gt;ServiceAccount&lt;&#x2F;code&gt; แยก user และออก token ใหม่ ก็ช่วยให้เชื่อมต่อได้อย่างปลอดภัย โดยไม่ต้องแชร์ cert หลักที่ฝังอยู่ในระบบ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;cert-based auth กับ token-based auth มีจุดเด่นต่างกัน&lt;&#x2F;strong&gt;
ถ้าใช้งานในระยะยาวหรือกับ user ที่สำคัญ ควรใช้ cert
แต่ถ้าใช้เฉพาะกิจหรือใน script ที่ rotate ได้ง่าย ก็ใช้ token ได้เลย&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;สุดท้าย ถ้ามีระบบที่ต้องให้คนอื่นเข้ามา access cluster หรืออยากเชื่อมต่อข้าม device อย่างปลอดภัย
Tailscale + RKE2 + การออก &lt;code&gt;kubeconfig&lt;&#x2F;code&gt; ที่ถูกต้อง ก็เป็นชุดที่ตอบโจทย์ได้แบบง่ายและมีประสิทธิภาพมาก ๆ โดยเฉพาะสำหรับ Homelab&lt;&#x2F;p&gt;
&lt;p&gt;ขอบคุณที่อ่านมาถึงตรงนี้ 🙌 ใครทำ Homelab เหมือนกัน ลองแชร์ประสบการณ์กันได้นะครับ 😎&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>How I Disabled Password Login on Ubuntu (And Why It Didn&#x27;t Work at First)</title>
		<published>2025-05-12T00:00:00+00:00</published>
		<updated>2025-05-12T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/disable-password-ubuntu-2025/" type="text/html"/>
		<id>https://thadaw.com/posts/disable-password-ubuntu-2025/</id>
		<content type="html">&lt;p&gt;I recently set up a small VM running Ubuntu and wanted to secure it a bit. One of the first things I usually do is disable SSH password authentication and use only key-based login. It’s more secure and makes SSH a lot more convenient if you’re jumping between machines often.&lt;&#x2F;p&gt;
&lt;p&gt;So I did the usual stuff:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Generated an SSH key using &lt;code&gt;ssh-keygen&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Copied the public key over with &lt;code&gt;ssh-copy-id&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Edited &lt;code&gt;&#x2F;etc&#x2F;ssh&#x2F;sshd_config&lt;&#x2F;code&gt; and set:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;PasswordAuthentication no
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Restarted the SSH service:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;sudo systemctl restart ssh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I tested it… and it &lt;strong&gt;still allowed password login&lt;&#x2F;strong&gt;. Weird.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;turns-out-ubuntu-cloud-init-strikes-again&quot;&gt;Turns out: Ubuntu cloud-init strikes again&lt;a class=&quot;zola-anchor&quot; href=&quot;#turns-out-ubuntu-cloud-init-strikes-again&quot; aria-label=&quot;Anchor link for: turns-out-ubuntu-cloud-init-strikes-again&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;After some digging, I found out that &lt;strong&gt;Ubuntu (especially cloud images or VMs provisioned via cloud-init)&lt;&#x2F;strong&gt; may create a file at:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;etc&#x2F;ssh&#x2F;sshd_config.d&#x2F;50-cloud-init.conf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This file can contain:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;PasswordAuthentication yes
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which overrides what you set in the main &lt;code&gt;sshd_config&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-i-fixed-it&quot;&gt;How I fixed it&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-i-fixed-it&quot; aria-label=&quot;Anchor link for: how-i-fixed-it&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Simple fix: I just removed the file.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;sudo rm -f &#x2F;etc&#x2F;ssh&#x2F;sshd_config.d&#x2F;50-cloud-init.conf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then restarted SSH again:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;sudo systemctl restart ssh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After that, I tested with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no user@host
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This time, it correctly rejected the password login with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Permission denied (publickey).
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;a class=&quot;zola-anchor&quot; href=&quot;#final-thoughts&quot; aria-label=&quot;Anchor link for: final-thoughts&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;I like how Ubuntu modularizes sshd config with the &lt;code&gt;sshd_config.d&lt;&#x2F;code&gt; directory, but it’s easy to miss overrides like this if you&#x27;re used to managing just a single file.&lt;&#x2F;p&gt;
&lt;p&gt;So if you’ve disabled password login and it’s &lt;strong&gt;still working&lt;&#x2F;strong&gt;, double-check that no other config file is sneaking in behind the scenes.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Reference:&lt;&#x2F;strong&gt;
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;askubuntu.com&#x2F;questions&#x2F;435615&#x2F;disable-password-authentication-in-ssh&quot;&gt;AskUbuntu – Disable password authentication in ssh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>บันทึการติดตั้ง Kubernetes Cluster ด้วย RKE2 ฉบับ Homelab</title>
		<published>2025-05-12T00:00:00+00:00</published>
		<updated>2025-05-12T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/note-setup-kube-rke2-homelab/" type="text/html"/>
		<id>https://thadaw.com/posts/note-setup-kube-rke2-homelab/</id>
		<content type="html">&lt;h2 id=&quot;aenanam-homelab-aelaepaahmaaykh-ngrabb&quot;&gt;แนะนำ Homelab และเป้าหมายของระบบ&lt;a class=&quot;zola-anchor&quot; href=&quot;#aenanam-homelab-aelaepaahmaaykh-ngrabb&quot; aria-label=&quot;Anchor link for: aenanam-homelab-aelaepaahmaaykh-ngrabb&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เริ่มจาก…มีเครื่อง PC วางทิ้งไว้ 2 ปี
ตอนแรกตั้งใจจะเอามาเล่นเกม เพราะมีการ์ดจอ AMD RX6600, CPU AMD 6 Core, RAM 32GB แบบสเปกดีอยู่นะ
แต่สุดท้ายก็ไม่ได้เล่นสักที... กลายเป็นโต๊ะวางฝุ่นไปเฉย 😅&lt;&#x2F;p&gt;
&lt;p&gt;คิดไปคิดมา...ไหน ๆ ก็ไม่ได้เล่นเกมละ งั้นเอามาทำ Homelab ละกัน
เสียดายอย่างเดียวคือ License Windows 11 หายจ้อย เพราะจำ Key ไม่ได้แล้ว 5555&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;p&gt;ผมไม่ค่อยได้ Setup Linux Server เท่าไหร่ ถ้าผมเขียนผมตรงไหน ฝากรบกวนแนะนำด้วยนะครับ&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;นี่ดูสิ Spec เหลือๆ
&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;note-setup-kube-rke2-homelab&#x2F;htop-pc.jpg&quot; alt=&quot;htop&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thamaimeluue-kaich-rke2&quot;&gt;ทำไมเลือกใช้ RKE2?&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaimeluue-kaich-rke2&quot; aria-label=&quot;Anchor link for: thamaimeluue-kaich-rke2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;จริง ๆ ตัวเลือกมันก็เยอะนะ ไม่ว่าจะเป็น:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubeadm&lt;&#x2F;code&gt; แบบคลาสสิก&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;k3s&lt;&#x2F;code&gt; ที่เบาแต่บางอย่างก็ตัดทิ้งไปเยอะ&lt;&#x2F;li&gt;
&lt;li&gt;หรือจะ &lt;code&gt;microk8s&lt;&#x2F;code&gt;, &lt;code&gt;kind&lt;&#x2F;code&gt;, &lt;code&gt;minikube&lt;&#x2F;code&gt; ก็มีนะ แต่ไม่ได้เลือกวันนี้&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;แต่สุดท้ายเลือก RKE2 เพราะ...&lt;&#x2F;p&gt;
&lt;p&gt;💡 มันคือ Kubernetes ที่:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;มี &lt;strong&gt;ทุกอย่างแบบ production-grade&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ใช้งานง่ายกว่า &lt;code&gt;kubeadm&lt;&#x2F;code&gt; เยอะ&lt;&#x2F;li&gt;
&lt;li&gt;มี binary เดียวติดตั้งแล้วจบ&lt;&#x2F;li&gt;
&lt;li&gt;ใช้ &lt;code&gt;containerd&lt;&#x2F;code&gt; ไม่ผูกกับ Docker&lt;&#x2F;li&gt;
&lt;li&gt;มี bundled etcd, kubelet, scheduler มาให้ครบ&lt;&#x2F;li&gt;
&lt;li&gt;และสำคัญสุดคือ... &lt;strong&gt;ไม่ต้องผูกกับ Rancher UI ก็ใช้ได้&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;แถม RKE2 ก็เป็นของ Rancher (SUSE) เหมือนกับ &lt;code&gt;k3s&lt;&#x2F;code&gt; นั่นแหละ&lt;&#x2F;p&gt;
&lt;p&gt;แต่ตัวนี้ &lt;strong&gt;เน้น production + HA จริงจังมากกว่า&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;แต่ก็นะ Spec เหลือๆ จะใช้ k3s ก็ดูถูก Spec ไปหน่อย 555 เลยลองอันที่น่าจะเอาไปใช้งานจริงได้ด้วยดีกว่า&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thamaimt-ngaeyk-disk-dwy-lvm&quot;&gt;ทำไมต้องแยก Disk ด้วย LVM?&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaimt-ngaeyk-disk-dwy-lvm&quot; aria-label=&quot;Anchor link for: thamaimt-ngaeyk-disk-dwy-lvm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เวลาทำ Homelab หลายคนชอบลง ๆ ไว้ใน &lt;code&gt;&#x2F;&lt;&#x2F;code&gt; หมดเลย
แต่พอทำจริง จะรู้เลยว่า:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;etcd กับ container runtime (containerd) มัน write เยอะมาก&lt;&#x2F;li&gt;
&lt;li&gt;log ก็พุ่ง&lt;&#x2F;li&gt;
&lt;li&gt;disk เต็ม → cluster พัง&lt;&#x2F;li&gt;
&lt;li&gt;หรือจะ move&#x2F;backup volume ทีนึงก็ลำบาก&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;เราเลยเลือกใช้ &lt;strong&gt;LVM เพื่อจัดการ disk แบบยืดหยุ่น&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;แยก disk path &lt;code&gt;&#x2F;var&#x2F;lib&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;opt&#x2F;kube-data&lt;&#x2F;code&gt; ออกจากกัน&lt;&#x2F;li&gt;
&lt;li&gt;เอา &lt;code&gt;&#x2F;var&#x2F;lib&lt;&#x2F;code&gt; ไปอยู่ SSD เพื่อให้ etcd&#x2F;containerd เร็ว&lt;&#x2F;li&gt;
&lt;li&gt;ทำ snapshot, resize, หรือย้าย path ได้ภายหลัง&lt;&#x2F;li&gt;
&lt;li&gt;และแยก HDD อีกตัวไว้สำรอง&#x2F;เก็บ log&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;epaahmaaykh-ngrabbnii&quot;&gt;เป้าหมายของระบบนี้&lt;a class=&quot;zola-anchor&quot; href=&quot;#epaahmaaykh-ngrabbnii&quot; aria-label=&quot;Anchor link for: epaahmaaykh-ngrabbnii&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เราอยากให้ Homelab ตัวนี้…&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;✅ ใช้ได้แบบ &lt;strong&gt;production จริง&lt;&#x2F;strong&gt; (run workload จริงได้)&lt;&#x2F;li&gt;
&lt;li&gt;✅ &lt;strong&gt;Scale&lt;&#x2F;strong&gt; ได้ในอนาคต (เพิ่ม Node ก็ได้)&lt;&#x2F;li&gt;
&lt;li&gt;✅ &lt;strong&gt;ไม่ผูกกับ distro&lt;&#x2F;strong&gt; ใด ๆ เช่น Rancher UI, k3s-only path&lt;&#x2F;li&gt;
&lt;li&gt;✅ เข้าใจว่าอะไรอยู่ตรงไหน ควบคุมได้เองหมด&lt;&#x2F;li&gt;
&lt;li&gt;✅ พร้อมใช้กับ Helm, Longhorn, GitOps, Monitoring ได้หมด&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;พูดง่าย ๆ คือมันจะเป็น “kube cluster ที่ไว้ใจได้”&lt;&#x2F;p&gt;
&lt;p&gt;เอาไว้ลองของจริงก่อนเอาไปใช้กับ production ข้างนอก&lt;&#x2F;p&gt;
&lt;h2 id=&quot;waangaephncchadkaar-disk-volume-aihphr-msamhrab-kubernetes&quot;&gt;วางแผนจัดการ Disk &#x2F; Volume ให้พร้อมสำหรับ Kubernetes&lt;a class=&quot;zola-anchor&quot; href=&quot;#waangaephncchadkaar-disk-volume-aihphr-msamhrab-kubernetes&quot; aria-label=&quot;Anchor link for: waangaephncchadkaar-disk-volume-aihphr-msamhrab-kubernetes&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ก่อนจะลง RKE2 ผมก็มานั่งคิดว่า...
ไหน ๆ ก็มี disk เยอะ ทำไมไม่จัดให้มันดีไปเลยตั้งแต่ต้น?&lt;&#x2F;p&gt;
&lt;p&gt;เครื่องที่ใช้มีทั้ง SSD และ HDD อยู่ในเครื่องเดียว:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SSD (NVMe 1TB)&lt;&#x2F;strong&gt; → ใช้ทำงานเร็ว ๆ เช่น OS, Database, PVC ที่ต้องการ IOPS&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;HDD (2TB)&lt;&#x2F;strong&gt; → ใช้เก็บ log, สำรองข้อมูล, ของที่ไม่ต้องอ่านเร็ว&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;พอรวมกับ LVM แล้ว เราก็จัดโครงสร้าง storage ได้แบบนี้เลย 👇&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ssd-nvme-samhrab-k8s-core-aela-data-thiit-ngkaarkhwaamerw&quot;&gt;SSD (NVMe): สำหรับ K8s Core และ Data ที่ต้องการความเร็ว&lt;a class=&quot;zola-anchor&quot; href=&quot;#ssd-nvme-samhrab-k8s-core-aela-data-thiit-ngkaarkhwaamerw&quot; aria-label=&quot;Anchor link for: ssd-nvme-samhrab-k8s-core-aela-data-thiit-ngkaarkhwaamerw&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Mountpoint&lt;&#x2F;th&gt;&lt;th&gt;ใช้ทำอะไร&lt;&#x2F;th&gt;&lt;th&gt;Volume&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ตัว OS Ubuntu&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;ubuntu-lv&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;var&#x2F;lib&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;เก็บ state ของ containerd, etcd, kubelet&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;varlib&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;opt&#x2F;kube-data&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;สำหรับ PVC แบบเร็ว เช่น PostgreSQL, Redis&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;kubedata&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;hdd-samhrabngaansamr-ng-log-cold-storage&quot;&gt;HDD: สำหรับงานสำรอง &#x2F; Log &#x2F; Cold Storage&lt;a class=&quot;zola-anchor&quot; href=&quot;#hdd-samhrabngaansamr-ng-log-cold-storage&quot; aria-label=&quot;Anchor link for: hdd-samhrabngaansamr-ng-log-cold-storage&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Mountpoint&lt;&#x2F;th&gt;&lt;th&gt;ใช้ทำอะไร&lt;&#x2F;th&gt;&lt;th&gt;หมายเหตุ&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;mnt&#x2F;storage-hdd&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;สำรองข้อมูล, log, rsync snapshot&lt;&#x2F;td&gt;&lt;td&gt;จาก &lt;code&gt;&#x2F;dev&#x2F;sda2&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;mnt&#x2F;storage-hdd2&lt;&#x2F;code&gt; &lt;em&gt;(optional)&lt;&#x2F;em&gt;&lt;&#x2F;td&gt;&lt;td&gt;สำรอง metadata หรือ media file&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&#x2F;dev&#x2F;sda3&lt;&#x2F;code&gt; ถ้าว่าง&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;logical-volume-thiisraangdwy-lvm&quot;&gt;Logical Volume ที่สร้างด้วย LVM&lt;a class=&quot;zola-anchor&quot; href=&quot;#logical-volume-thiisraangdwy-lvm&quot; aria-label=&quot;Anchor link for: logical-volume-thiisraangdwy-lvm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;LV Name&lt;&#x2F;th&gt;&lt;th&gt;Mountpoint&lt;&#x2F;th&gt;&lt;th&gt;ใช้ทำอะไร&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;root&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ระบบ OS&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;varlib&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&#x2F;var&#x2F;lib&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ส่วนที่ K8s ใช้หลัก ๆ (etcd, containerd)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;kubedata&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&#x2F;opt&#x2F;kube-data&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;PVC สำหรับ Database &#x2F; Log เร็ว ๆ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;hlakkaar-kaebb-volume-ngaay&quot;&gt;หลักการออกแบบ Volume ง่าย ๆ&lt;a class=&quot;zola-anchor&quot; href=&quot;#hlakkaar-kaebb-volume-ngaay&quot; aria-label=&quot;Anchor link for: hlakkaar-kaebb-volume-ngaay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ผมคิดไว้ว่า...&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ไม่อยากให้ K8s ใช้ path แบบ &lt;code&gt;rancher&#x2F;&lt;&#x2F;code&gt;, &lt;code&gt;k3s&#x2F;&lt;&#x2F;code&gt; หรืออะไรที่ &quot;ผูกกับ distro&quot;&lt;&#x2F;li&gt;
&lt;li&gt;อยากตั้งชื่อ path แบบกลาง ๆ เช่น &lt;code&gt;&#x2F;opt&#x2F;kube-data&lt;&#x2F;code&gt; หรือ &lt;code&gt;&#x2F;var&#x2F;lib&lt;&#x2F;code&gt; ที่ควบคุมเองได้&lt;&#x2F;li&gt;
&lt;li&gt;เวลาอยากย้าย cluster ก็แค่ย้าย folder หรือ LV ไปเท่านั้น&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;แถมด้วยข้อดีของ LVM:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Resize ได้ง่าย&lt;&#x2F;li&gt;
&lt;li&gt;Snap ได้&lt;&#x2F;li&gt;
&lt;li&gt;แยก log &#x2F; etcd ออกจากกันไม่ให้ disk เต็มรวมหัวกัน&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;taw-yaang-use-case-cchring&quot;&gt;ตัวอย่าง Use Case จริง ๆ&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaang-use-case-cchring&quot; aria-label=&quot;Anchor link for: taw-yaang-use-case-cchring&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;งาน&lt;&#x2F;th&gt;&lt;th&gt;Path&lt;&#x2F;th&gt;&lt;th&gt;ประเภท Storage&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;etcd, containerd, kubelet&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&#x2F;var&#x2F;lib&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;SSD (เร็วมาก)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PostgreSQL &#x2F; Redis PVC&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&#x2F;opt&#x2F;kube-data&#x2F;postgres&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;SSD&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Media uploads &#x2F; backup logs&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&#x2F;mnt&#x2F;storage-hdd&#x2F;uploads&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;HDD&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;สำรอง snapshot&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&#x2F;mnt&#x2F;storage-hdd&#x2F;backup&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;HDD&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;ต่อจากนี้ก็จะเริ่มสร้าง LV, mount, format และเตรียมไว้ให้ RKE2 ใช้งานได้เลย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lngmuue-cchadkaar-lvm-aeyk-disk-aih-k8s-aichngaanaidyaaw-rocket&quot;&gt;ลงมือจัดการ LVM แยก Disk ให้ K8s ใช้งานได้ยาว ๆ 🚀&lt;a class=&quot;zola-anchor&quot; href=&quot;#lngmuue-cchadkaar-lvm-aeyk-disk-aih-k8s-aichngaanaidyaaw-rocket&quot; aria-label=&quot;Anchor link for: lngmuue-cchadkaar-lvm-aeyk-disk-aih-k8s-aichngaanaidyaaw-rocket&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลังจากลง Ubuntu 24.04 LTS เสร็จ ผมก็เช็คสเปกพื้นฐานก่อนด้วยคำสั่ง &lt;code&gt;lsb_release -a&lt;&#x2F;code&gt; กับ &lt;code&gt;uname -a&lt;&#x2F;code&gt;
เพื่อให้แน่ใจว่า kernel ใหม่ ๆ พร้อมใช้งาน และรองรับระบบ LVM กับ container runtime ได้ดี&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; lsb_release&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Distributor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ID: Ubuntu&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Description:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;    Ubuntu 24.04.2 LTS&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; uname&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Linux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; XXXX 6.8.0-59-generic ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ที่ผมติดตั้งมาใช้ LVM แบบอัตโนมัติเรียบร้อย
เพราะอยากให้จัดการ Disk ได้ง่ายขึ้น โดยไม่ต้อง Format ใหม่ทุกครั้งที่อยากเพิ่ม volume&lt;&#x2F;p&gt;
&lt;h3 id=&quot;echkhokhrngsraang-disk-thiimii-yuuk-n&quot;&gt;เช็คโครงสร้าง disk ที่มีอยู่ก่อน&lt;a class=&quot;zola-anchor&quot; href=&quot;#echkhokhrngsraang-disk-thiimii-yuuk-n&quot; aria-label=&quot;Anchor link for: echkhokhrngsraang-disk-thiimii-yuuk-n&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; lsblk&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                      MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sda&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                         8:0    0   1.8T  0 disk &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├─sda1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                      8:1    0    16M  0 part &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├─sda2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                      8:2    0 886.4G  0 part &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;└─sda3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                      8:3    0 976.6G  0 part &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nvme0n1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                   259:0    0 931.5G  0 disk &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├─nvme0n1p1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;               259:1    0     1G  0 part &#x2F;boot&#x2F;efi&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├─nvme0n1p2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;               259:2    0     2G  0 part &#x2F;boot&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;└─nvme0n1p3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;               259:3    0 928.5G  0 part &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;└─ubuntu--vg-ubuntu--lv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 252:0    0   100G  0 lvm  &#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จะเห็นว่า:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;มี SSD (nvme0n1) ขนาด ~1TB แบ่งเป็น 3 พาร์ติชัน ใช้ LVM อยู่แล้ว&lt;&#x2F;li&gt;
&lt;li&gt;และมี HDD (sda) อีก 2 พาร์ติชันใหญ่ ๆ รวมประมาณ 1.8TB&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ในตอนแรก root (&lt;code&gt;&#x2F;&lt;&#x2F;code&gt;) ถูก mount ไว้ที่ LV ชื่อ &lt;code&gt;ubuntu-lv&lt;&#x2F;code&gt; ขนาด 100GB
และ volume group ชื่อ &lt;code&gt;ubuntu-vg&lt;&#x2F;code&gt; ยังเหลืออีกเพียบ! ประมาณ 828GB 😍&lt;&#x2F;p&gt;
&lt;p&gt;ก่อนจะเริ่มแบ่งพื้นที่จริง เรามาสำรวจ Volume Group ที่ Ubuntu ติดตั้งให้อัตโนมัติไว้ก่อน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo vgdisplay&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Volume group ---&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;VG&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Name               ubuntu-vg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Format&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                lvm2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;VG&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Access             read&#x2F;write&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;VG&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Status             resizable&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;VG&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Size               928.46 GiB&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Alloc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; PE &#x2F; Size       25600 &#x2F; 100.00 GiB&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Free&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;  PE &#x2F; Size       212085 &#x2F; 828.46 GiB&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากผลคำสั่ง vgdisplay จะเห็นว่า Ubuntu ติดตั้งมาแบบใช้ LVM ให้เรียบร้อยแล้ว
โดยมี Volume Group ชื่อ ubuntu-vg ขนาดรวมประมาณ 928GB&lt;&#x2F;p&gt;
&lt;p&gt;ตอนนี้ใช้ไปแค่ 100GB สำหรับ &#x2F; เท่านั้นเอง
พื้นที่ที่เหลือยังมีอีกเกือบ 830GB แบบ resizable ด้วย
แปลว่าเราสามารถสร้าง Logical Volume เพิ่มได้อีกสบาย ๆ 🎉&lt;&#x2F;p&gt;
&lt;h3 id=&quot;maaerimsraang-lvm-ephimkanely-tada&quot;&gt;มาเริ่มสร้าง LVM เพิ่มกันเลย 🎉&lt;a class=&quot;zola-anchor&quot; href=&quot;#maaerimsraang-lvm-ephimkanely-tada&quot; aria-label=&quot;Anchor link for: maaerimsraang-lvm-ephimkanely-tada&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เป้าหมายคือ...&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Mountpoint&lt;&#x2F;th&gt;&lt;th&gt;ขนาด&lt;&#x2F;th&gt;&lt;th&gt;ใช้ทำอะไร&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;var&#x2F;lib&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;100GB&lt;&#x2F;td&gt;&lt;td&gt;เก็บ state ของ containerd ฯลฯ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;opt&#x2F;kube-data&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;200GB&lt;&#x2F;td&gt;&lt;td&gt;PVC &#x2F; database &#x2F; log ที่ต้องการ IOPS&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; lvcreate&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;n&lt;&#x2F;span&gt; varlib&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;L&lt;&#x2F;span&gt; 100G ubuntu-vg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; lvcreate&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;n&lt;&#x2F;span&gt; kubedata&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;L&lt;&#x2F;span&gt; 200G ubuntu-vg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;format-mount-thiilacchud&quot;&gt;Format + Mount ทีละจุด&lt;a class=&quot;zola-anchor&quot; href=&quot;#format-mount-thiilacchud&quot; aria-label=&quot;Anchor link for: format-mount-thiilacchud&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Format&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkfs.ext4 &#x2F;dev&#x2F;ubuntu-vg&#x2F;varlib&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkfs.ext4 &#x2F;dev&#x2F;ubuntu-vg&#x2F;kubedata&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; เตรียมโฟลเดอร์ mount&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkdir&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;p&lt;&#x2F;span&gt; &#x2F;mnt&#x2F;varlib &#x2F;opt&#x2F;kube-data&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; mount ชั่วคราวเพื่อย้ายของใน &#x2F;var&#x2F;lib&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mount &#x2F;dev&#x2F;ubuntu-vg&#x2F;varlib &#x2F;mnt&#x2F;varlib&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; cp&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a&lt;&#x2F;span&gt; &#x2F;var&#x2F;lib&#x2F;&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;*&lt;&#x2F;span&gt; &#x2F;mnt&#x2F;varlib&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; เปลี่ยนตัวจริง&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mv &#x2F;var&#x2F;lib &#x2F;var&#x2F;lib.bak&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkdir &#x2F;var&#x2F;lib&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mount &#x2F;dev&#x2F;ubuntu-vg&#x2F;varlib &#x2F;var&#x2F;lib&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นเพิ่มเข้า &lt;code&gt;&#x2F;etc&#x2F;fstab&lt;&#x2F;code&gt; เพื่อให้ system mount ให้อัตโนมัติหลัง reboot:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&#x2F;dev&#x2F;ubuntu-vg&#x2F;varlib &#x2F;var&#x2F;lib ext4 defaults 0 2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; tee&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a&lt;&#x2F;span&gt; &#x2F;etc&#x2F;fstab&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&#x2F;dev&#x2F;ubuntu-vg&#x2F;kubedata &#x2F;opt&#x2F;kube-data ext4 defaults 0 2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; tee&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a&lt;&#x2F;span&gt; &#x2F;etc&#x2F;fstab&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;cchadphuuenthii-backup-bn-hdd&quot;&gt;จัดพื้นที่ backup บน HDD&lt;a class=&quot;zola-anchor&quot; href=&quot;#cchadphuuenthii-backup-bn-hdd&quot; aria-label=&quot;Anchor link for: cchadphuuenthii-backup-bn-hdd&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ต่อไปเราจะเตรียม &lt;code&gt;&#x2F;mnt&#x2F;storage-hdd&lt;&#x2F;code&gt; สำหรับสำรอง log หรือ DB snapshot ต่าง ๆ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkfs.ext4 &#x2F;dev&#x2F;sda2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkdir&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;p&lt;&#x2F;span&gt; &#x2F;mnt&#x2F;storage-hdd&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mount &#x2F;dev&#x2F;sda2 &#x2F;mnt&#x2F;storage-hdd&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&#x2F;dev&#x2F;sda2 &#x2F;mnt&#x2F;storage-hdd ext4 defaults 0 2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; tee&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a&lt;&#x2F;span&gt; &#x2F;etc&#x2F;fstab&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;echkhsthaanahlang-mount&quot;&gt;เช็คสถานะหลัง mount&lt;a class=&quot;zola-anchor&quot; href=&quot;#echkhsthaanahlang-mount&quot; aria-label=&quot;Anchor link for: echkhsthaanahlang-mount&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;grep&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;E&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&#x2F;var&#x2F;lib|&#x2F;opt&#x2F;kube-data|&#x2F;mnt&#x2F;storage-hdd&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จะได้เห็นว่า:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&#x2F;var&#x2F;lib&lt;&#x2F;code&gt; ใช้ &lt;code&gt;varlib&lt;&#x2F;code&gt; จาก SSD แล้วจริง ๆ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;opt&#x2F;kube-data&lt;&#x2F;code&gt; พร้อมใช้งาน&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;mnt&#x2F;storage-hdd&lt;&#x2F;code&gt; พร้อมสำรอง log แล้ว&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;srup-logical-volume-thiimiit-nnii&quot;&gt;สรุป Logical Volume ที่มีตอนนี้&lt;a class=&quot;zola-anchor&quot; href=&quot;#srup-logical-volume-thiimiit-nnii&quot; aria-label=&quot;Anchor link for: srup-logical-volume-thiimiit-nnii&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo lvs&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;LV&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;        VG         LSize&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ubuntu-lv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ubuntu-vg  100.00g  (สำหรับ &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;varlib&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;    ubuntu-vg  100.00g  (สำหรับ &#x2F;var&#x2F;lib&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubedata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;  ubuntu-vg  200.00g  (สำหรับ &#x2F;opt&#x2F;kube-data&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;และยังเหลือพื้นที่ใน VG (&lt;code&gt;ubuntu-vg&lt;&#x2F;code&gt;) อีกประมาณ &lt;strong&gt;528GB&lt;&#x2F;strong&gt;
เอาไว้ขยายในอนาคตได้อีก&lt;&#x2F;p&gt;
&lt;p&gt;ดู mountpoint ด้วย:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; lsblk&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; NAME,SIZE,FSTYPE,MOUNTPOINT,LABEL&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                        SIZE FSTYPE      MOUNTPOINT       LABEL&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sda&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                         1.8T                              &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├─sda1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                       16M                              &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├─sda2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                    886.4G ext4        &#x2F;mnt&#x2F;storage-hdd &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;└─sda3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                    976.6G ntfs                         Entertain&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nvme0n1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                   931.5G                              &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├─nvme0n1p1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                   1G vfat        &#x2F;boot&#x2F;efi        &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├─nvme0n1p2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;                   2G ext4        &#x2F;boot            &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;└─nvme0n1p3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;               928.5G LVM2_member                  &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├─ubuntu--vg-ubuntu--lv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   100G ext4        &#x2F;                &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;├─ubuntu--vg-varlib&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;       100G ext4        &#x2F;var&#x2F;lib         &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;└─ubuntu--vg-kubedata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;     200G ext4        &#x2F;opt&#x2F;kube-data   &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นก็ ทดสอบ reboot สักรอบ แล้วเช็คว่า mount ถูกต้อง&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mount&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;grep&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;E&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&#x2F;var&#x2F;lib|&#x2F;opt&#x2F;kube-data|&#x2F;mnt&#x2F;storage-hdd&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&#x2F;dev&#x2F;mapper&#x2F;ubuntu--vg-kubedata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; on &#x2F;opt&#x2F;kube-data type ext4 (rw,relatime&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&#x2F;dev&#x2F;mapper&#x2F;ubuntu--vg-varlib&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; on &#x2F;var&#x2F;lib type ext4 (rw,relatime&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&#x2F;dev&#x2F;sda2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; on &#x2F;mnt&#x2F;storage-hdd type ext4 (rw,relatime&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จะเห็นว่า mount ถูกต้องตามที่เราตั้งใจไว้&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tidtang-rke2-bn-ubuntu&quot;&gt;ติดตั้ง RKE2 บน Ubuntu&lt;a class=&quot;zola-anchor&quot; href=&quot;#tidtang-rke2-bn-ubuntu&quot; aria-label=&quot;Anchor link for: tidtang-rke2-bn-ubuntu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ต่อไปเราจะติดตั้ง RKE2 บน Ubuntu 24.04 LTS&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-tidtang-binary-kh-ng-rke2&quot;&gt;1. ติดตั้ง Binary ของ RKE2&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-tidtang-binary-kh-ng-rke2&quot; aria-label=&quot;Anchor link for: 1-tidtang-binary-kh-ng-rke2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;RKE2 ใช้ installer ตัวเดียวจบเลย ไม่ต้องแยกลง kubelet, etcd อะไรให้วุ่นวาย
แค่รันคำสั่งนี้ก็พร้อมติดตั้งทุกอย่าง&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;curl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;sfL&lt;&#x2F;span&gt; https:&#x2F;&#x2F;get.rke2.io&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sh -&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ระบบจะโหลด binary มาไว้ที่ &lt;code&gt;&#x2F;usr&#x2F;local&lt;&#x2F;code&gt; และติดตั้งแบบ systemd service ให้อัตโนมัติเลย&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-enable-aela-start-service&quot;&gt;2. Enable และ Start Service&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-enable-aela-start-service&quot; aria-label=&quot;Anchor link for: 2-enable-aela-start-service&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; systemctl enable rke2-server.service&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; systemctl start rke2-server.service&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;แนะนำให้รันแยกกัน เพื่อถ้ามี error ตอน &lt;code&gt;start&lt;&#x2F;code&gt; จะได้ดู log ทันที&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;3-duu-log-realtime&quot;&gt;3. ดู Log Realtime&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-duu-log-realtime&quot; aria-label=&quot;Anchor link for: 3-duu-log-realtime&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ระหว่างรอ service ทำงาน ผมแนะนำให้เปิด log ดูไว้ก่อนเลย:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; journalctl&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;u&lt;&#x2F;span&gt; rke2-server&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถ้า service ทำงานปกติ จะเจอบรรทัดประมาณนี้:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; class=&quot;language-text z-code&quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Remotedialer connected to proxy
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Adding node &amp;lt;ชื่อเครื่อง&amp;gt; etcd status condition
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Tunnel authorizer set Kubelet Port 0.0.0.0:10250
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;🕐 ปกติใช้เวลาประมาณ 1–2 นาทีตอนรันครั้งแรก เพราะต้องโหลด container image ต่าง ๆ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4-trwcchs-b-node-dwy-kubectl&quot;&gt;4. ตรวจสอบ Node ด้วย kubectl&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-trwcchs-b-node-dwy-kubectl&quot; aria-label=&quot;Anchor link for: 4-trwcchs-b-node-dwy-kubectl&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;RKE2 จะมี &lt;code&gt;kubectl&lt;&#x2F;code&gt; ของมันเองอยู่ใน path:
&lt;code&gt;&#x2F;var&#x2F;lib&#x2F;rancher&#x2F;rke2&#x2F;bin&#x2F;kubectl&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าเรายังไม่มี &lt;code&gt;kubectl&lt;&#x2F;code&gt; ใน system path ก็สร้าง symlink ไปไว้ที่ &lt;code&gt;&#x2F;usr&#x2F;local&#x2F;bin&lt;&#x2F;code&gt; เลย:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ln&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;s&lt;&#x2F;span&gt; &#x2F;var&#x2F;lib&#x2F;rancher&#x2F;rke2&#x2F;bin&#x2F;kubectl &#x2F;usr&#x2F;local&#x2F;bin&#x2F;kubectl&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นลองรัน:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; get nodes&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถ้าขึ้นแบบนี้ แปลว่าใช้งานได้เรียบร้อย 🎉&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; class=&quot;language-text z-code&quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;NAME       STATUS   ROLES                       AGE   VERSION
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;homelab    Ready    control-plane,etcd,master   3m    v1.31.x+rke2r1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;สรุปตอนนี้&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;RKE2 ติดตั้งและรันสำเร็จ&lt;&#x2F;li&gt;
&lt;li&gt;kubectl พร้อมใช้งานจากเครื่อง server&lt;&#x2F;li&gt;
&lt;li&gt;node status เป็น Ready แล้ว&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;tangkhaa-kubectl-bnekhruue-ng-mac-aihechuue-mt-rke2&quot;&gt;ตั้งค่า &lt;code&gt;kubectl&lt;&#x2F;code&gt; บนเครื่อง Mac ให้เชื่อมต่อ RKE2&lt;a class=&quot;zola-anchor&quot; href=&quot;#tangkhaa-kubectl-bnekhruue-ng-mac-aihechuue-mt-rke2&quot; aria-label=&quot;Anchor link for: tangkhaa-kubectl-bnekhruue-ng-mac-aihechuue-mt-rke2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลังจาก RKE2 สร้าง cluster สำเร็จแล้ว
จะมีไฟล์ชื่อ &lt;code&gt;rke2.yaml&lt;&#x2F;code&gt; อยู่ที่:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&#x2F;etc&#x2F;rancher&#x2F;rke2&#x2F;rke2.yaml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ไฟล์นี้คือ &lt;strong&gt;kubeconfig&lt;&#x2F;strong&gt; ที่ใช้สั่ง &lt;code&gt;kubectl&lt;&#x2F;code&gt; เชื่อมเข้า cluster ได้เลย
แต่ต้องระวังนิดนึงเพราะมันเป็น cert-based admin user ที่มีสิทธิ์เต็ม ⚠️&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-khadl-k-rke2-yaml-maathii-home-directory&quot;&gt;1. คัดลอก &lt;code&gt;rke2.yaml&lt;&#x2F;code&gt; มาที่ home directory&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-khadl-k-rke2-yaml-maathii-home-directory&quot; aria-label=&quot;Anchor link for: 1-khadl-k-rke2-yaml-maathii-home-directory&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; cp &#x2F;etc&#x2F;rancher&#x2F;rke2&#x2F;rke2.yaml &#x2F;home&#x2F;&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;your-user&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&#x2F;rke2.yaml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; chown &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;your-user&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;:&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;your-user&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &#x2F;home&#x2F;&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;your-user&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&#x2F;rke2.yaml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;เปลี่ยน &lt;code&gt;&amp;lt;your-user&amp;gt;&lt;&#x2F;code&gt; เป็นชื่อจริงของ user บนเครื่อง&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;2-cchaak-mac-aich-scp-duengaiflmaa&quot;&gt;2. จาก Mac ใช้ &lt;code&gt;scp&lt;&#x2F;code&gt; ดึงไฟล์มา&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-cchaak-mac-aich-scp-duengaiflmaa&quot; aria-label=&quot;Anchor link for: 2-cchaak-mac-aich-scp-duengaiflmaa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;scp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;my_home_lab&#x2F;id_rsa &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;user&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;@&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;ip-server&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;:&#x2F;home&#x2F;&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;user&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&#x2F;rke2.yaml &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.kube&#x2F;rke2.yaml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เช่น:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;scp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;my_home_lab&#x2F;id_rsa thadawth@192.168.1.107:&#x2F;home&#x2F;thadawth&#x2F;rke2.yaml &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.kube&#x2F;rke2.yaml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;3-epliiynchuue-context-cluster-user-dwy-yq-aihduudiikhuen&quot;&gt;3. เปลี่ยนชื่อ context&#x2F;cluster&#x2F;user ด้วย &lt;code&gt;yq&lt;&#x2F;code&gt; ให้ดูดีขึ้น&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-epliiynchuue-context-cluster-user-dwy-yq-aihduudiikhuen&quot; aria-label=&quot;Anchor link for: 3-epliiynchuue-context-cluster-user-dwy-yq-aihduudiikhuen&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ตอนนี้ทุกชื่อใน &lt;code&gt;rke2.yaml&lt;&#x2F;code&gt; จะชื่อว่า &lt;code&gt;default&lt;&#x2F;code&gt; หมดเลย
เราจะเปลี่ยนให้มันเท่ ๆ เช่น:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;context → &lt;code&gt;my_homelab&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;cluster → &lt;code&gt;my_homelab-cluster&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;user → &lt;code&gt;my_homelab-user&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ผมเตรียม script ให้ใช้เลย &lt;code&gt;rename-kubeconfig.sh&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; 📌 รับ argument&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;CONTEXT_NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;CLUSTER_NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;USER_NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;KUBECONFIG_PATH&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.kube&#x2F;rke2.yaml&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; ✅ ตรวจสอบ input&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-if z-shell&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-double-brace z-begin z-shell&quot;&gt;[[&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;-&lt;&#x2F;span&gt;z&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;CONTEXT_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-shell&quot;&gt;||&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;-&lt;&#x2F;span&gt;z&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;CLUSTER_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-shell&quot;&gt;||&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;-&lt;&#x2F;span&gt;z&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;USER_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-double-brace z-end z-shell&quot;&gt;]]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-continue z-shell&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-conditional z-then z-shell&quot;&gt;then&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;❌ Usage: &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &amp;lt;context_name&amp;gt; &amp;lt;cluster_name&amp;gt; &amp;lt;user_name&amp;gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-exit z-shell&quot;&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-end z-shell&quot;&gt;fi&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; ✅ เช็คว่า yq ติดตั้งแล้ว&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-if z-shell&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-shell&quot;&gt;!&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-command z-shell&quot;&gt;command&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;-&lt;&#x2F;span&gt;v&lt;&#x2F;span&gt; yq &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;amp;&amp;gt;&lt;&#x2F;span&gt; &#x2F;dev&#x2F;null&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-continue z-shell&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-conditional z-then z-shell&quot;&gt;then&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;❌ &amp;#39;yq&amp;#39; not found. Install it with &amp;#39;brew install yq&amp;#39;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-exit z-shell&quot;&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-end z-shell&quot;&gt;fi&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;🔧 Updating kubeconfig: &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;KUBECONFIG_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;➡️  Context: &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;CONTEXT_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;➡️  Cluster: &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;CLUSTER_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;➡️  User: &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;USER_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; 🔁 แก้ชื่อทั้งหมด in-place&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;yq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;(.clusters[] | select(.name == &lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;default&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;) | .name) = &lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;CLUSTER_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;KUBECONFIG_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;yq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;(.clusters[] | select(.name == &lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;CLUSTER_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;) | .cluster.server) = &lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;https:&#x2F;&#x2F;192.168.1.107:6443&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;KUBECONFIG_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;yq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;(.users[] | select(.name == &lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;default&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;) | .name) = &lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;USER_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;KUBECONFIG_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;yq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;(.contexts[] | select(.name == &lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;default&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;) | .name) = &lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;CONTEXT_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;KUBECONFIG_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;yq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;  (.contexts[] | select(.name == &lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;CONTEXT_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;) | .context.cluster) = &lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;CLUSTER_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt; |
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;  (.contexts[] | select(.name == &lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;CONTEXT_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;) | .context.user) = &lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;USER_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;KUBECONFIG_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;yq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;.current-context = &lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;CONTEXT_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;KUBECONFIG_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;✅ Done! You can now merge it into ~&#x2F;.kube&#x2F;config with:&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;   KUBECONFIG=~&#x2F;.kube&#x2F;config:&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;KUBECONFIG_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; kubectl config view --flatten &amp;gt; &#x2F;tmp&#x2F;config &amp;amp;&amp;amp; mv &#x2F;tmp&#x2F;config ~&#x2F;.kube&#x2F;config&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นก็ให้สิทธิ์ execute ให้กับ script&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;chmod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; +x rename-kubeconfig.sh&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;.&#x2F;rename-kubeconfig.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; my_homelab my_homelab-cluster my_homelab-defaultUser&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;4-rwm-rke2-yaml-ekhaakab-kubeconfig-hlak&quot;&gt;4. รวม &lt;code&gt;rke2.yaml&lt;&#x2F;code&gt; เข้ากับ kubeconfig หลัก&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-rwm-rke2-yaml-ekhaakab-kubeconfig-hlak&quot; aria-label=&quot;Anchor link for: 4-rwm-rke2-yaml-ekhaakab-kubeconfig-hlak&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-shell&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;KUBECONFIG&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.kube&#x2F;config:&lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.kube&#x2F;rke2.yaml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; config view&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;flatten&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &#x2F;tmp&#x2F;kubeconfig-merged.yaml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.kube&#x2F;config &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.kube&#x2F;config.bak&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;tmp&#x2F;kubeconfig-merged.yaml &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.kube&#x2F;config&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ลองดูว่า context ที่เราตั้งไว้มีอยู่มั้ย:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; config get-contexts&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;CURRENT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   NAME                     CLUSTER                  AUTHINFO                                               NAMESPACE&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;           &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;my_homelab&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;               my_homelab-cluster       my_homelab-defaultUser                                 &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;          rancher-desktop          rancher-desktop          rancher-desktop       &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ไม่ต้องไปสนใจว่า &lt;code&gt;rancher-desktop&lt;&#x2F;code&gt; มาจากไหนนะ พอผมใช้ &lt;code&gt;rancher-desktop&lt;&#x2F;code&gt; อยู่ด้วย&lt;&#x2F;p&gt;
&lt;h3 id=&quot;5-tang-context-aihmaihepnkhaa-default&quot;&gt;5. ตั้ง context ใหม่ให้เป็นค่า default&lt;a class=&quot;zola-anchor&quot; href=&quot;#5-tang-context-aihmaihepnkhaa-default&quot; aria-label=&quot;Anchor link for: 5-tang-context-aihmaihepnkhaa-default&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; kubectl config use-context my_homelab&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ลองดูว่าเชื่อมได้มั้ย:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; kubectl get nodes&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;       STATUS   ROLES                       AGE   VERSION&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;USER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   Ready    control-plane,etcd,master   66m   v1.31.8+rke2r1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เย้ 🎉 ถ้าเห็น node ขึ้นจาก Mac ก็แปลว่าเชื่อมต่อสำเร็จ!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;deploy-ae-paerkbn-rke2-nginx-adult-fried-egg&quot;&gt;Deploy แอปแรกบน RKE2: NGINX 🧑‍🍳&lt;a class=&quot;zola-anchor&quot; href=&quot;#deploy-ae-paerkbn-rke2-nginx-adult-fried-egg&quot; aria-label=&quot;Anchor link for: deploy-ae-paerkbn-rke2-nginx-adult-fried-egg&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เราจะเริ่มจากการ deploy nginx แบบง่าย ๆ เพื่อ:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ทดสอบว่า cluster ใช้งานได้จริง&lt;&#x2F;li&gt;
&lt;li&gt;เข้าใจแนวทาง deploy แบบ basic&lt;&#x2F;li&gt;
&lt;li&gt;พร้อมใช้ &lt;code&gt;kubectl&lt;&#x2F;code&gt;, &lt;code&gt;svc&lt;&#x2F;code&gt;, และ &lt;code&gt;port-forward&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;1-sraangaifl-nginx-deploy-yaml&quot;&gt;1. สร้างไฟล์ &lt;code&gt;nginx-deploy.yaml&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-sraangaifl-nginx-deploy-yaml&quot; aria-label=&quot;Anchor link for: 1-sraangaifl-nginx-deploy-yaml&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;apps&#x2F;v1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;kind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Deployment&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;nginx-deployment&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;labels&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;nginx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;spec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;replicas&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-yaml&quot;&gt;1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;selector&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;matchLabels&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;nginx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;template&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;labels&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;nginx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;spec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;containers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;nginx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;nginx:stable&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;ports&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;containerPort&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-yaml&quot;&gt;80&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-other z-document z-begin z-yaml&quot;&gt;---&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;v1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;kind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Service&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;nginx-service&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;spec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;selector&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;nginx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;ports&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;port&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-yaml&quot;&gt;80&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;targetPort&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-yaml&quot;&gt;80&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;ClusterIP&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;📦 จะได้ทั้ง &lt;code&gt;Deployment&lt;&#x2F;code&gt; และ &lt;code&gt;Service&lt;&#x2F;code&gt; แบบ ClusterIP&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;2-apply-manifest&quot;&gt;2. Apply manifest&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-apply-manifest&quot; aria-label=&quot;Anchor link for: 2-apply-manifest&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; apply&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt; nginx-deploy.yaml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;3-trwcchs-bsthaana&quot;&gt;3. ตรวจสอบสถานะ&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-trwcchs-bsthaana&quot; aria-label=&quot;Anchor link for: 3-trwcchs-bsthaana&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; get deploy,pods,svc&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถ้าทุกอย่างปกติจะเห็นแบบนี้:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; class=&quot;language-text z-code&quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;deployment.apps&#x2F;nginx-deployment   1&#x2F;1     1            1           15s
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;NAME             TYPE        CLUSTER-IP      PORT(S)   AGE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;nginx-service    ClusterIP   10.43.XXX.XXX   80&#x2F;TCP    15s
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;4-ekhaaphaan-mac-dwy-port-forward-withiierwthiisud&quot;&gt;4. เข้าผ่าน Mac ด้วย &lt;code&gt;port-forward&lt;&#x2F;code&gt; (วิธีเร็วที่สุด)&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-ekhaaphaan-mac-dwy-port-forward-withiierwthiisud&quot; aria-label=&quot;Anchor link for: 4-ekhaaphaan-mac-dwy-port-forward-withiierwthiisud&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; port-forward svc&#x2F;nginx-service 8080:80&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แล้วเปิด browser ไปที่:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;http:&#x2F;&#x2F;localhost:8080
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;เย้~ จะเจอหน้า “Welcome to nginx!” แล้ว 🎉&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;note-setup-kube-rke2-homelab&#x2F;nginx-up.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aenwthaangeruue-ng-security-rawang-rke2-yaml-aihdii&quot;&gt;แนวทางเรื่อง Security: ระวัง rke2.yaml ให้ดี&lt;a class=&quot;zola-anchor&quot; href=&quot;#aenwthaangeruue-ng-security-rawang-rke2-yaml-aihdii&quot; aria-label=&quot;Anchor link for: aenwthaangeruue-ng-security-rawang-rke2-yaml-aihdii&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลังจากที่เรา copy &lt;code&gt;rke2.yaml&lt;&#x2F;code&gt; มาใช้บน Mac แล้ว เชื่อมต่อ cluster ได้ — เยี่ยมมาก!
แต่ต้องรู้ไว้ว่า...&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ ไฟล์ &lt;code&gt;rke2.yaml&lt;&#x2F;code&gt; คือ &lt;strong&gt;admin cert เต็มรูปแบบ&lt;&#x2F;strong&gt;
ใครได้ไฟล์นี้ = เหมือนได้ root access บน Kubernetes cluster ทันที&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;มันเป็น cert แบบ client certificate ที่ฝังไว้ใน &lt;code&gt;user.client-certificate-data&lt;&#x2F;code&gt;
ซึ่ง RKE2 auto-generate มาให้เราใช้งานได้สะดวกสุด ๆ
แต่ในแง่ความปลอดภัย ถ้าเราจะใช้งานหลายเครื่อง หรือแชร์ cluster ให้คนอื่นใช้ → ไม่ควรใช้ตัวนี้ต่อ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;withiiaenanam-aeyk-serviceaccount-taamphuuaichngaan&quot;&gt;วิธีแนะนำ: แยก ServiceAccount ตามผู้ใช้งาน&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiiaenanam-aeyk-serviceaccount-taamphuuaichngaan&quot; aria-label=&quot;Anchor link for: withiiaenanam-aeyk-serviceaccount-taamphuuaichngaan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ใน Kubernetes เราสามารถสร้าง user แบบจำกัดสิทธิ์ได้ง่าย ๆ ผ่าน ServiceAccount
ซึ่งเป็นวิธีที่เบา ปลอดภัย และไม่ต้องยุ่งกับ cert เองเลย&lt;&#x2F;p&gt;
&lt;h3 id=&quot;taw-yaang-sraang-admin-user-aebb-read-write&quot;&gt;ตัวอย่าง: สร้าง &lt;code&gt;admin-user&lt;&#x2F;code&gt; แบบ read&#x2F;write&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaang-sraang-admin-user-aebb-read-write&quot; aria-label=&quot;Anchor link for: taw-yaang-sraang-admin-user-aebb-read-write&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create serviceaccount admin-user&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;n&lt;&#x2F;span&gt; kube-system&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; create clusterrolebinding admin-user-binding &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;  --&lt;&#x2F;span&gt;clusterrole&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;cluster-admin &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;  --&lt;&#x2F;span&gt;serviceaccount&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;kube-system:admin-user&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;สร้าง account ที่มีสิทธิ์เท่ากับ cluster-admin&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;sraang-token-ephuue-echuue-mt&quot;&gt;สร้าง token เพื่อเชื่อมต่อ&lt;a class=&quot;zola-anchor&quot; href=&quot;#sraang-token-ephuue-echuue-mt&quot; aria-label=&quot;Anchor link for: sraang-token-ephuue-echuue-mt&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;n&lt;&#x2F;span&gt; kube-system create token admin-user&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จะได้ token string เอาไว้ใช้กับ &lt;code&gt;kubectl config&lt;&#x2F;code&gt; หรือใส่ใน CI&#x2F;CD ก็ได้&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ehmaaakabaikhr&quot;&gt;เหมาะกับใคร?&lt;a class=&quot;zola-anchor&quot; href=&quot;#ehmaaakabaikhr&quot; aria-label=&quot;Anchor link for: ehmaaakabaikhr&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;สถานการณ์&lt;&#x2F;th&gt;&lt;th&gt;ใช้แบบไหนดี&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;ใช้เครื่องเดียว&lt;&#x2F;td&gt;&lt;td&gt;ใช้ &lt;code&gt;rke2.yaml&lt;&#x2F;code&gt; ได้เลย ✅&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;แชร์ให้คนอื่นใช้&lt;&#x2F;td&gt;&lt;td&gt;สร้าง ServiceAccount แยก&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ทำระบบจริง&lt;&#x2F;td&gt;&lt;td&gt;ใช้ OIDC หรือ cert-manager&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;sngthaay-cchaakekhruue-ngthiin-nechy-cluster-thiiaichaidcchring&quot;&gt;ส่งท้าย: จากเครื่องที่นอนเฉย ๆ → Cluster ที่ใช้ได้จริง&lt;a class=&quot;zola-anchor&quot; href=&quot;#sngthaay-cchaakekhruue-ngthiin-nechy-cluster-thiiaichaidcchring&quot; aria-label=&quot;Anchor link for: sngthaay-cchaakekhruue-ngthiin-nechy-cluster-thiiaichaidcchring&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ทั้งหมดนี้คือเส้นทางของการเปลี่ยน “PC วางทิ้งไว้ 2 ปี” ให้กลายเป็น &lt;strong&gt;Kubernetes Cluster พร้อมใช้งานจริงในบ้าน&lt;&#x2F;strong&gt;
จากจุดที่ยังไม่มีอะไรเลย — เราเริ่มด้วยการ:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;✅ ติดตั้ง Ubuntu และจัดการ disk ด้วย LVM&lt;&#x2F;li&gt;
&lt;li&gt;✅ วางแผนพื้นที่ใช้งานแยกชัดเจน (เร็ว &#x2F; ใหญ่ &#x2F; สำรอง)&lt;&#x2F;li&gt;
&lt;li&gt;✅ ติดตั้ง RKE2 และ config ให้ควบคุมผ่านเครื่อง Mac ได้&lt;&#x2F;li&gt;
&lt;li&gt;✅ deploy nginx สำเร็จเป็นแอปแรกบน cluster&lt;&#x2F;li&gt;
&lt;li&gt;✅ พร้อมวางรากฐานเรื่อง security, user และการขยายต่อในอนาคต&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ทั้งหมดนี้ไม่ใช่แค่ setup แล้วจบ
แต่มันคือการวาง “โครงสร้าง” ที่เราจะต่อยอดไปได้อีกไกลมาก 🎯&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aelwt-aipcchatham-aair&quot;&gt;แล้วต่อไปจะทำอะไร?&lt;a class=&quot;zola-anchor&quot; href=&quot;#aelwt-aipcchatham-aair&quot; aria-label=&quot;Anchor link for: aelwt-aipcchatham-aair&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ใน Part ต่อ ๆ ไป ผมจะพาไปลุยของจริงกันแบบจัดเต็ม เช่น...&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;🌐 ติดตั้ง Ingress Controller เพื่อให้เข้าแอปจากข้างนอกได้แบบ domain name&lt;&#x2F;li&gt;
&lt;li&gt;🔐 วางระบบ User &#x2F; RBAC ให้แชร์ cluster แบบปลอดภัย&lt;&#x2F;li&gt;
&lt;li&gt;📦 ติดตั้ง Helm, CSI Storage (Longhorn), และ GitOps&lt;&#x2F;li&gt;
&lt;li&gt;📊 Monitoring &#x2F; Logging แบบที่ production ต้องมี&lt;&#x2F;li&gt;
&lt;li&gt;🔄 รองรับ CI&#x2F;CD จาก GitHub&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ป.ล. อันนี้ก็ฝันไปก่อนนะ มีเวลาว่างเมื่อไหร่ค่อยว่ากันละกันนะ อิอิ&lt;&#x2F;p&gt;
&lt;p&gt;อย่าลืมติดตาม Part ถัดไปนะ 💬
ถ้าใครอยากลองทำตาม ผมรับรองว่าทำได้จริง (มั้งนะ) และสนุกมากแน่นอน 💙&lt;&#x2F;p&gt;
&lt;p&gt;แล้วเจอกันตอนหน้า! 😄✨&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>แก้ปัญหา TS5055: Cannot write file because it would overwrite input file</title>
		<published>2025-03-27T00:00:00+00:00</published>
		<updated>2025-03-27T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/fix-ts5055-cannot-write-file-overwrite-input/" type="text/html"/>
		<id>https://thadaw.com/posts/fix-ts5055-cannot-write-file-overwrite-input/</id>
		<content type="html">&lt;p&gt;ช่วงที่ผมกำลังพัฒนา library ตัวหนึ่งชื่อว่า &lt;code&gt;kubricate&lt;&#x2F;code&gt; ซึ่งเป็น framework สำหรับจัดการ Kubernetes manifests ด้วย TypeScript ผมตั้งค่าให้ build แบบ dual output ทั้ง ESM และ CJS โดยใช้ TypeScript compile ไปที่ &lt;code&gt;dist&#x2F;esm&lt;&#x2F;code&gt; และ Babel แปลงเป็น &lt;code&gt;dist&#x2F;cjs&lt;&#x2F;code&gt; ต่อ&lt;&#x2F;p&gt;
&lt;p&gt;ทุกอย่างดูเหมือนจะโอเค จนกระทั่งเปิด &lt;code&gt;declaration: true&lt;&#x2F;code&gt; เพื่อให้ generate ไฟล์ &lt;code&gt;.d.ts&lt;&#x2F;code&gt; แล้วตั้ง &lt;code&gt;declarationDir&lt;&#x2F;code&gt; ไว้ที่ &lt;code&gt;dist&#x2F;dts&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;payhaathiiecch&quot;&gt;ปัญหาที่เจอ&lt;a class=&quot;zola-anchor&quot; href=&quot;#payhaathiiecch&quot; aria-label=&quot;Anchor link for: payhaathiiecch&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;พอรัน &lt;code&gt;tsc&lt;&#x2F;code&gt; ปุ๊บ ก็เจอ error แบบนี้เลย:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;error TS5055: Cannot write file ‘&#x2F;path&#x2F;to&#x2F;project&#x2F;dist&#x2F;dts&#x2F;internal&#x2F;utils.d.ts’ because it would overwrite input file.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ซึ่งตอนแรกก็งงว่า &quot;นี่เราทำอะไรผิดตรงไหนหรือเปล่า?&quot; เพราะเราไม่ได้แก้ไขไฟล์ใน &lt;code&gt;dist&lt;&#x2F;code&gt; โดยตรงเลย ไฟล์ทั้งหมดอยู่ใน &lt;code&gt;src&lt;&#x2F;code&gt; ชัด ๆ&lt;&#x2F;p&gt;
&lt;p&gt;พอดูดี ๆ ก็เห็นว่า TypeScript พยายาม compile แล้วจะเขียนไฟล์ &lt;code&gt;.d.ts&lt;&#x2F;code&gt; ไปยัง &lt;code&gt;dist&#x2F;dts&#x2F;...&lt;&#x2F;code&gt; แต่ดันเข้าใจว่าไฟล์พวกนั้นเป็น &lt;strong&gt;ไฟล์ต้นทาง&lt;&#x2F;strong&gt; (input) ด้วย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aekyangaing&quot;&gt;แก้ยังไง&lt;a class=&quot;zola-anchor&quot; href=&quot;#aekyangaing&quot; aria-label=&quot;Anchor link for: aekyangaing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ผมลองไล่ดู config หลายจุด และสุดท้ายก็เจอว่า ตัวแปรสำคัญคือ &lt;code&gt;&quot;exclude&quot;&lt;&#x2F;code&gt; ใน &lt;code&gt;tsconfig.json&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;พอเช็กไฟล์ดู พบว่า &lt;code&gt;dist&#x2F;&lt;&#x2F;code&gt; ไม่ได้อยู่ใน &lt;code&gt;&quot;exclude&quot;&lt;&#x2F;code&gt; ทำให้ TypeScript มองว่าไฟล์เก่าใน &lt;code&gt;dist&lt;&#x2F;code&gt; คือ input ของการ compile&lt;&#x2F;p&gt;
&lt;h3 id=&quot;withiiaek&quot;&gt;วิธีแก้:&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiiaek&quot; aria-label=&quot;Anchor link for: withiiaek&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;เพิ่ม &lt;code&gt;&quot;dist&quot;&lt;&#x2F;code&gt; เข้าไปใน &lt;code&gt;exclude&lt;&#x2F;code&gt; ของ &lt;code&gt;tsconfig.json&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json z-code&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;compilerOptions&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;rootDir&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;src&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;outDir&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dist&#x2F;esm&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;declarationDir&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dist&#x2F;dts&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;declaration&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;exclude&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;node_modules&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-json&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dist&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-json&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;*.config.ts&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;ลบโฟลเดอร์ dist&#x2F; ให้สะอาดก่อนรัน tsc ใหม่:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;```sh
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;rm -rf dist
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;tsc
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;สรุป&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าใครเจอ Error แบบ &lt;code&gt;TS5055: Cannot write file ... because it would overwrite input file.&lt;&#x2F;code&gt; ให้เช็กสองอย่างหลัก ๆ คือ:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;มีการตั้งค่า outDir หรือ declarationDir ซ้อนกับ path ที่เคยมี output ไว้หรือเปล่า&lt;&#x2F;li&gt;
&lt;li&gt;ลืมใส่ &quot;dist&quot; ไว้ใน exclude หรือเปล่า&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;แค่นั้นเลยครับ เพิ่ม dist เข้าไปใน exclude แล้วลบของเก่าออกก่อน build ทุกครั้ง ก็จบเลย&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>เจอปัญหา Error Type ของ TypeScript แบบแปลก ๆ เพราะไม่ได้ติดตั้ง dependency?</title>
		<published>2025-03-27T00:00:00+00:00</published>
		<updated>2025-03-27T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/typescript-type-error-from-missing-dependency/" type="text/html"/>
		<id>https://thadaw.com/posts/typescript-type-error-from-missing-dependency/</id>
		<content type="html">&lt;p&gt;ช่วงนี้ผมกำลังทำ npm package สำหรับจัดการ stack ต่าง ๆ ใน Kubernetes โดยใช้ไลบรารี &lt;code&gt;kubernetes-models&lt;&#x2F;code&gt; ร่วมกับระบบ controller ที่ผมเขียนเองชื่อว่า &lt;code&gt;kubricate&lt;&#x2F;code&gt; ซึ่งทุกอย่างดูจะโอเคดี แต่พอเขียนเป็น class และมี method ที่เรียกใช้ &lt;code&gt;new KubricateController().add(...)&lt;&#x2F;code&gt; แล้วคืนค่าออกมา TypeScript ก็เริ่มร้อง&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;payhaathiiecch&quot;&gt;ปัญหาที่เจอ&lt;a class=&quot;zola-anchor&quot; href=&quot;#payhaathiiecch&quot; aria-label=&quot;Anchor link for: payhaathiiecch&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ตัวอย่างจากรูปเลยนะ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;typescript-type-error-from-missing-dependency&#x2F;.&#x2F;typescript-error.png&quot; alt=&quot;TypeScript Error&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;TypeScript แจ้งว่า:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The inferred type of configureStack cannot be named without a reference to &lt;code&gt;.pnpm&#x2F;@kubernetes-models+base@5.0.1&#x2F;node_modules&#x2F;@kubernetes-models&#x2F;base&lt;&#x2F;code&gt; . This is likely not portable. A type annotation is necessary.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ในตอนแรก ผมงงมาก เพราะผมไม่ได้ import &lt;code&gt;@kubernetes-models&#x2F;base&lt;&#x2F;code&gt; โดยตรง แต่ใช้แค่ &lt;code&gt;kubernetes-models&lt;&#x2F;code&gt; ที่ดูเหมือนจะครบแล้ว ทำให้ TypeScript ไม่สามารถ resolve type ได้แบบ portable และคิดว่ามันอาจจะมีปัญหาเวลาใช้งานข้ามโปรเจกต์หรือ publish เป็น package&lt;&#x2F;p&gt;
&lt;p&gt;ผมลองแก้หลายแบบ:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ใส่ return type ด้วย &lt;code&gt;ReturnType&amp;lt;...&amp;gt;&lt;&#x2F;code&gt; ก็ทำให้ type หาย ไม่ตรงกับที่ต้องการ&lt;&#x2F;li&gt;
&lt;li&gt;แยก method ออกมาเป็นฟังก์ชันข้างนอก class ก็ยังไม่ได้&lt;&#x2F;li&gt;
&lt;li&gt;เปลี่ยนเป็น static method ก็ยังเจอ error เดิม&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;สุดท้ายสิ่งที่เวิร์กที่สุดกลับง่ายกว่าที่คิด&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;withiithiiaekaidcchring&quot;&gt;วิธีที่แก้ได้จริง&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiithiiaekaidcchring&quot; aria-label=&quot;Anchor link for: withiithiiaekaidcchring&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลังจากสังเกตข้อความดี ๆ จาก Error: มันมีการพูดถึง package ตัวนึงที่ไม่คุ้นเคยเลย &lt;code&gt;@kubernetes-models&#x2F;base&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ผมเริ่มสงสัยว่ามันพยายามจะ reference ไปที่ &lt;code&gt;@kubernetes-models&#x2F;base&lt;&#x2F;code&gt; โดยตรง ซึ่ง TypeScript ใช้ในการ resolve ชนิดของ object ที่ return ออกมา แต่พอลองเข้าไปเช็กจริง ๆ ใน &lt;code&gt;node_modules&lt;&#x2F;code&gt; กลับไม่เจอ path นี้อยู่เลย&lt;&#x2F;p&gt;
&lt;p&gt;ตรงนี้ทำให้แน่ใจว่า package &lt;code&gt;@kubernetes-models&#x2F;base&lt;&#x2F;code&gt; ไม่ได้ถูกติดตั้งอยู่ในระบบจริง ๆ แม้ว่า &lt;code&gt;kubernetes-models&lt;&#x2F;code&gt; จะใช้งานได้ก็ตาม พอเพิ่ม dependency ที่ขาดหายไปเข้าไปให้ครบ ก็ไม่มีปัญหาอีกต่อไป&lt;&#x2F;p&gt;
&lt;p&gt;ผมลองติดตั้ง &lt;code&gt;@kubernetes-models&#x2F;base&lt;&#x2F;code&gt; โดยตรงเพิ่มเข้าไปในโปรเจกต์ด้วยคำสั่ง:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;pnpm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; add @kubernetes-models&#x2F;base&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ทันทีที่ติดตั้งเสร็จ TypeScript ก็หยุดร้อง ไม่มี error ใด ๆ อีกเลย ทั้ง ๆ ที่ผมไม่ได้ใช้ @kubernetes-models&#x2F;base โดยตรงในไฟล์นั้นด้วยซ้ำ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;srup&quot;&gt;สรุป&lt;a class=&quot;zola-anchor&quot; href=&quot;#srup&quot; aria-label=&quot;Anchor link for: srup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ปัญหานี้เกิดจาก TypeScript พยายาม infer ชนิดของค่าที่ได้จากไลบรารี ซึ่งเบื้องหลังจริง ๆ แล้วไปอิง type ที่อยู่ใน @kubernetes-models&#x2F;base แต่เราไม่ได้ติดตั้งไว้ มันเลยโยน warning ว่า type ไม่สามารถใช้งานแบบ portable ได้&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าใครเจอปัญหาคล้าย ๆ กัน โดยเฉพาะเวลาใช้ไลบรารีที่มี dependency ซ้อนกันหลายชั้น และ TypeScript เริ่มพูดถึง inferred type แบบ &quot;cannot be named without a reference...&quot; ให้ลองเช็กดูว่าไลบรารีที่เกี่ยวข้องจริง ๆ ถูกติดตั้งไว้หรือยัง&lt;&#x2F;p&gt;
&lt;p&gt;การติดตั้งไลบรารีที่ขาดหายไปอาจเป็นวิธีที่ง่ายที่สุดและถูกต้องที่สุดในการแก้ปัญหาแบบนี้&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ป.ล. ปัญหานี้ไปถาม GPT ละ มันก็ตอบไม่ได้เหมือนกัน 555 เลยเอามาเขียนเป็นบทความ น่าจะเป็นประโยชน์กับใครที่เจอปัญหาเดียวกัน&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ไปละ บุย&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>บันทึกการแก้ปัญหา ioctopus และการทำให้ Type-Safe ผ่าน TypeScript โดยใช้ AI</title>
		<published>2025-03-19T00:00:00+00:00</published>
		<updated>2025-03-19T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/note-for-ioctopus-type-safe-typescript-ai/" type="text/html"/>
		<id>https://thadaw.com/posts/note-for-ioctopus-type-safe-typescript-ai/</id>
		<content type="html">&lt;p&gt;วันนี้จะมาคุยกันเรื่อง Dependency Injection (DI) ใน TypeScript โดยเฉพาะปัญหาที่เกิดขึ้นเมื่อใช้ DI บน Edge Runtime เช่น Vercel Edge ซึ่งเป็นข้อจำกัดของบาง Library ที่ใช้ Reflection API&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Background: Dependency Injection ใน Framework ดังๆ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;หลายๆ คนที่เขียน Backend กันอยู่แล้ว อาจจะเคยใช้ Framework พวก Nest.js หรือถ้า .NET หรือ Java Spring Boot สิ่งที่ Framework พวกนี้ทำคล้ายๆ กันก็คือ เรื่องของ Decorator สำหรับทำ Dependency Injection และใช่ครับ นั่นเป็นหนึ่งใน Use Case ที่พบเห็นได้ทั่วไป และเป็นส่วนประกอบสำคัญของระบบระบบถอดประกอบส่วนต่างๆ ได้ อย่างเช่น Clean Architecture ของ ลุง Bob...&lt;&#x2F;p&gt;
&lt;p&gt;ตัวอย่างใน Nest.js:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;Controller&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;Get&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;@nestjs&#x2F;common&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-decorator z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-decorator z-ts&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;Controller&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;example&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;ExampleController&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-decorator z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-decorator z-ts&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;Get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;getHello&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Hello, NestJS!&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แต่จริงๆ แล้ว Dependency Injection ไม่จำเป็นต้องใช้ decorator ก็ได้นะ&lt;&#x2F;p&gt;
&lt;p&gt;การที่ library ใน Node.js จะใช้ decorator เพื่อทำ Dependency Injection มันต้องใช้ Reflection API (Reflect-metadata) เพื่อที่จะทำให้มันเกิดได้ แต่มันปัญหาก็คือมันผูกอยู่กับ Node.js Runtime กับพวกอื่นๆ ถ้าเราจะทำให้มันทำงานทุก Runtime ได้ ตรงนี้จึงไม่ตอบโจทย์&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aerngcchuungaicch-thamaimthueng-yaakaich-ioctopus&quot;&gt;แรงจูงใจ: ทำไมถึงอยากใช้ ioctopus?&lt;a class=&quot;zola-anchor&quot; href=&quot;#aerngcchuungaicch-thamaimthueng-yaakaich-ioctopus&quot; aria-label=&quot;Anchor link for: aerngcchuungaicch-thamaimthueng-yaakaich-ioctopus&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ช่วงที่ทำระบบ Dependency Injection (DI) ต้องการหา Runtime Agnostic Library ที่รองรับ Edge Runtime ของ Vercel หรือ Runtime อื่นๆ ได้ โดยที่ไม่ต้องใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.npmjs.com&#x2F;package&#x2F;reflect-metadata&quot;&gt;Reflection API&lt;&#x2F;a&gt; ซึ่งเป็นข้อจำกัดของ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;inversify&#x2F;InversifyJS&quot;&gt;Inversify&lt;&#x2F;a&gt; ทำให้ได้ลองใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Evyweb&#x2F;ioctopus&quot;&gt;@evyweb&#x2F;ioctopus&lt;&#x2F;a&gt; ซึ่งถูกออกแบบมาเพื่อลดความซับซ้อนและช่วยให้โค้ดสะอาดขึ้น&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;version ของ @evyweb&#x2F;ioctopus ณ ตอนนี้เป็นเวอร์ชั่น 1.2.0&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;จริงๆ ไม่ใช่เฉพาะ Inversify นะ พวก DI ดังๆ อย่าง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;microsoft&#x2F;tsyringe&quot;&gt;Tsyringe&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;typestack&#x2F;typedi&quot;&gt;Typedi&lt;&#x2F;a&gt; เองก็มีปัญหาเดียวกัน ที่ไม่สามารถใช้งานได้บน Edge Runtime ได้ สามารถไปดูจากวิดิโอและ github ของทางผู้สร้าง from &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Yliaah4oiZY&quot;&gt;YouTube&lt;&#x2F;a&gt; และ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nikolovlazar&#x2F;nextjs-clean-architecture&#x2F;pull&#x2F;11&quot;&gt;Next.js Clean Architecture PR&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;อ่านเพิ่มเติมเรื่อง Refection API ได้ที่นี่นะ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;blog.bitsrc.io&#x2F;typescripts-reflect-metadata-what-it-is-and-how-to-use-it-fb7b19cfc7e2&quot;&gt;TypeScript’s Reflect Metadata: What it is and How to Use it&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;โดยปกติแล้ว ioctopus มีการใช้งานดังนี้:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;CurriedFunctionWithDependencies&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-return z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;curriedFunctionWithDependencies&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;dep1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;CurriedFunctionWithDependencies&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Hello &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; with &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dep1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Step 1: สร้าง DI เป็น Symbol&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;DI&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;InjectionTokens&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;DEP1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-builtin z-ts&quot;&gt;Symbol&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;DEP1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;DEP2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-builtin z-ts&quot;&gt;Symbol&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;DEP2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;HIGHER_ORDER_FUNCTION_WITH_DEPENDENCIES&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-builtin z-ts&quot;&gt;Symbol&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;HIGHER_ORDER_FUNCTION_WITH_DEPENDENCIES&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Step 2: สร้าง Container&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createContainer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Step 3: เริ่มผูกความสัมพันธ์ของ Dependencies ว่าแต่ละ Dependencies จะไปหาในไหน&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;bind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-object z-ts&quot;&gt;DI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-property z-ts&quot;&gt;DEP1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toValue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;dependency1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;bind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-object z-ts&quot;&gt;DI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-property z-ts&quot;&gt;DEP2&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toValue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;42&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;bind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;CURRIED_FUNCTION_WITH_DEPENDENCIES&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toCurry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;curriedFunctionWithDependencies&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-object z-ts&quot;&gt;DI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-property z-ts&quot;&gt;DEP1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Step 4: ใช้งาน Dependencies ผ่าน Container&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ตรงนี้เราจะได้ Data จาก Dependencies ที่ผูกไว้ก่อนหน้า และเอาไปใช้งานได้จริง&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;myService&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;MyServiceInterface&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-object z-ts&quot;&gt;DI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-property z-ts&quot;&gt;HIGHER_ORDER_FUNCTION_WITH_DEPENDENCIES&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แต่ปัญหาของ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Evyweb&#x2F;ioctopus&quot;&gt;@evyweb&#x2F;ioctopus&lt;&#x2F;a&gt; พบว่าเราไม่สามารถทำให้เกิด Type Safety ได้เลย
เพราะไม่ว่าเราจะ Bind หรือตอนที่เราใช้ &lt;code&gt;toCurry&lt;&#x2F;code&gt; ใน dependencies เราใส่ Symbol แต่เราต้องใส่อะไรเข้าไปบ้าง ไม่มีการระบุ Type ของ Dependencies ที่เราใช้งาน ดังนั้นใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;ioctopus&#x2F;pull&#x2F;2&#x2F;file&quot;&gt;@thaitype&#x2F;ioctopus&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;โดยที่มีเป้าหมายให้ Type-safety โดย จะเปลี่ยนเป็น&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Step 1: สร้าง serivceRegistry และกำหนด Type ของแต่ละ Dependencies โดยที่ไม่ต้องสร้าง Symbol เอง เพราะ serviceRegistry จะทำการ Map ให้เอง&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;serviceRegistry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ServiceRegistry&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;define&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;DEP1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;mapTo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;define&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;DEP2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;mapTo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;define&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;CURRIED_FUNCTION_WITH_DEPENDENCIES&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;mapTo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;CurriedFunctionWithDependencies&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Step 2: สร้าง Container โดยที่รับ serviceRegistry เข้าไป&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createContainer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;serviceRegistry&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;bind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;DEP1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toValue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;dependency1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;bind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;DEP2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toValue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;42&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;bind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;CURRIED_FUNCTION_WITH_DEPENDENCIES&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toCurry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;curriedFunctionWithDependencies&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;DEP1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Step 3: ใช้งาน Dependencies ผ่าน Container&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;myService&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;CURRIED_FUNCTION_WITH_DEPENDENCIES&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถ้าสังเกตุจากโค๊ด เราจะเห็นว่าเราไม่ต้องมี &lt;code&gt;DI&lt;&#x2F;code&gt; object แล้ว และเราสามารถกำหนด Type ของ Dependencies ได้ใน &lt;code&gt;serviceRegistry&lt;&#x2F;code&gt; และเราสามารถใช้งาน Dependencies ได้ผ่าน &lt;code&gt;container.get&lt;&#x2F;code&gt; โดยที่ไม่ต้องใช้ Symbol อีกต่อไป และเราจะรู้เลยว่าเราใส่ค่าถูกต้องหรือไม่ เพราะมันจะบอก Type ให้เราทันที&lt;&#x2F;p&gt;
&lt;p&gt;เช่น ตอนที่เราใช้แบบนี้ มันจะ Error เพราะว่า &lt;code&gt;curriedFunctionWithDependencies&lt;&#x2F;code&gt; ต้องการ DEP1 เป็น string แต่เราใส่เป็น number&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;bind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;CURRIED_FUNCTION_WITH_DEPENDENCIES&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toCurry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;curriedFunctionWithDependencies&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;DEP2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;หมายเหตุ: ณ เวลาที่เขียน function &lt;code&gt;toCurry&lt;&#x2F;code&gt; ใน @thaitype&#x2F;ioctopus ยังบอก type ผิดอยู่ แต่ถ้าใช้ &lt;code&gt;toHigherOrderFunction&lt;&#x2F;code&gt; จะบอก Type ถูก เดี๋ยวจะแก้อีกทีนะ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ตัวอย่าง Type-safety&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;note-for-ioctopus-type-safe-typescript-ai&#x2F;.&#x2F;thaitype-ioctopus.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;klabmaathiiocchthykh-ngwanniikan&quot;&gt;กลับมาที่โจทย์ของวันนี้กัน&lt;a class=&quot;zola-anchor&quot; href=&quot;#klabmaathiiocchthykh-ngwanniikan&quot; aria-label=&quot;Anchor link for: klabmaathiiocchthykh-ngwanniikan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เนื่องจากอาจจะตามกันไม่ทัน สามารถไปดูตัวอย่างโค๊ดเต็มๆ ได้ที่นี่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;ioctopus&#x2F;pull&#x2F;2&#x2F;files&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;ioctopus&#x2F;pull&#x2F;2&#x2F;files&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;คือการเปลี่ยนโค้ดจาก:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;myService&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;MyServiceInterface&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;serviceRegistry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;HIGHER_ORDER_FUNCTION_WITH_DEPENDENCIES&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;มาเป็นรูปแบบที่อ่านง่ายขึ้นแบบนี้ และ Type-safe โดยรับแค่ key ของ serviceRegistry มาเท่านั้น:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;myService&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;container&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;HIGHER_ORDER_FUNCTION_WITH_DEPENDENCIES&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เพราะ &lt;code&gt;createContainer(serviceRegistry)&lt;&#x2F;code&gt; ได้รับ serviceRegistry อยู่แล้ว เลยไม่จำเป็นต้อง &lt;code&gt;serviceRegistry.get(...)&lt;&#x2F;code&gt; ก่อนเรียก &lt;code&gt;container.get(...)&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;และเพื่อให้เห็นภาพมากขึ้นเราลองมาดูตัวอย่างโค๊ดกัน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createContainer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Services&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;serviceRegistry&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ServiceRegistry&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Services&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Container&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Services&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; 📌 A&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;serviceRegistry (before get):&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;serviceRegistry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;keyMap&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;DependencyKeyType&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Services&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; 📌 B&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;serviceRegistry (after get):&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;serviceRegistry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;keyMap&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;dependencyKey&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;serviceRegistry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dependencyKey&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;            &lt;span class=&quot;z-keyword z-control z-trycatch z-ts&quot;&gt;throw&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Error&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;No key found for dependency: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dependencyKey&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;       &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;get&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;🔥 ปัญหาที่เจอ: Unit Test ไม่ผ่าน เพราะ &lt;code&gt;serviceRegistry.get(...)&lt;&#x2F;code&gt; คืนค่า undefined&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ป.ล. ใน Class ServiceRegistry จะมี field ที่ชื่อ keyMap ที่เก็บ key ของ service ทั้งหมดไว้ ดูที่โค๊ด &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;ioctopus&#x2F;blob&#x2F;master.type-safe.container-get-type-safe&#x2F;src&#x2F;service-registry.ts#L2&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;ioctopus&#x2F;blob&#x2F;master.type-safe.container-get-type-safe&#x2F;src&#x2F;service-registry.ts#L2&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;หลังจากเปลี่ยนโค้ดและรัน Unit Test บน Jest &#x2F; Vitest กลับพบว่า:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;serviceRegistry.keyMap&lt;&#x2F;code&gt; ตอนเริ่มต้น มีค่า (ตรง 📌 A)&lt;&#x2F;li&gt;
&lt;li&gt;แต่ตอน &lt;code&gt;get(...)&lt;&#x2F;code&gt; ค่า &lt;code&gt;serviceRegistry.get(dependency)&lt;&#x2F;code&gt; กลับ &lt;code&gt;undefined&lt;&#x2F;code&gt; (ตรง 📌 B)&lt;&#x2F;li&gt;
&lt;li&gt;ทำให้เกิด Error:&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Error: No key found for dependency: undefined
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ตอนแรก คิดว่าเป็นปัญหาจาก Jest &#x2F; Vitest Runtime เพราะใน AI ก็บอกมาแบบนั้น แต่เมื่อไปรันบน Node.js ตรงๆ กลับพบว่า ไม่เกี่ยวเลย! จากที่เคยเข้าใจว่า&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;แต่ตอน get(...) ค่า serviceRegistry.get(dependency) กลับ undefined (ตรง 📌 B)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;เราดันไปเข้าใจว่า &lt;code&gt;serviceRegistry.keyMap&lt;&#x2F;code&gt; มันเป็น object ว่าง เกิดจาที่ AI บอกว่า serviceRegistry มากกว่าหนึ่งตัว แต่จริงๆ แล้วมันมีแค่ตัวเดียว และเราก็ไม่ได้มีปัญหาเรื่อง Duplicate Imports หรือ Circular Dependency ด้วย&lt;&#x2F;p&gt;
&lt;p&gt;ปัญหาที่แท้จริงคือ container เรียก &lt;code&gt;get(...)&lt;&#x2F;code&gt; หลายรอบ โดยที่ไม่ได้เข้าใจกลไกของโค๊ดทั้งหมด และในการเรียกซ้ำ มันใช้ Symbol ที่ resolve มาแล้วแทน String Key เดิม ซึ่งทำให้ &lt;code&gt;serviceRegistry.get(...)&lt;&#x2F;code&gt; ไม่สามารถหา Symbol ได้ เพราะใน serviceRegistry มันเก็บเป็น String Key ไม่ใช่ Symbol ของ Key&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cchudthiiekhaaaicchphid-khidwaapayhaakhuue-serviceregistry-thuuksraangcham&quot;&gt;จุดที่เข้าใจผิด: คิดว่าปัญหาคือ serviceRegistry ถูกสร้างซ้ำ&lt;a class=&quot;zola-anchor&quot; href=&quot;#cchudthiiekhaaaicchphid-khidwaapayhaakhuue-serviceregistry-thuuksraangcham&quot; aria-label=&quot;Anchor link for: cchudthiiekhaaaicchphid-khidwaapayhaakhuue-serviceregistry-thuuksraangcham&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ช่วงแรกมั่นใจมากว่า ปัญหาคือมี serviceRegistry มากกว่าหนึ่งตัว เพราะ AI (GPT-4 o1) พยายามตอบไปในทางนั้นซ้ำๆ ว่า:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Ensure every place references the same instance (imported from a single path, with no duplicates or circular imports).”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;แต่จริงๆ แล้ว:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;serviceRegistry ถูกสร้าง แค่ครั้งเดียว&lt;&#x2F;li&gt;
&lt;li&gt;ไม่มีปัญหาเรื่อง Duplicate Imports&lt;&#x2F;li&gt;
&lt;li&gt;ไม่มีปัญหาเรื่อง Circular Dependency&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ซึ่งทำให้เสียเวลามากกว่าที่ควรจะเป็น เพราะต้องคุยกับ AI หลาย Prompt จนกว่ามันจะเสนอคำตอบอื่นที่ใกล้เคียงกับปัญหาจริง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cchudthiiecch-hlangranbn-node-js&quot;&gt;จุดที่เจอหลังรันบน Node.js&lt;a class=&quot;zola-anchor&quot; href=&quot;#cchudthiiecch-hlangranbn-node-js&quot; aria-label=&quot;Anchor link for: cchudthiiecch-hlangranbn-node-js&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลังจากลอง Debug บน Node.js โดยไม่ผ่าน Jest &#x2F; Vitest ก็พบว่า:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;ตอน &lt;code&gt;get(...)&lt;&#x2F;code&gt; ครั้งแรก: &lt;code&gt;container.get(&#x27;DEP1&#x27;);&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ระบบเอา &lt;code&gt;&quot;DEP1&quot;&lt;&#x2F;code&gt; ไปหา &lt;code&gt;Symbol(‘DEP1’)&lt;&#x2F;code&gt; จาก serviceRegistry.keyMap&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;แต่พอ &lt;code&gt;get(...)&lt;&#x2F;code&gt; ครั้งต่อมา: &lt;code&gt;container.get(Symbol(&#x27;DEP1&#x27;));&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;มันใช้ &lt;code&gt;Symbol(‘DEP1’)&lt;&#x2F;code&gt; ที่ได้มาแล้ว ไปหาใน &lt;code&gt;serviceRegistry.keyMap&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;แต่ &lt;code&gt;keyMap&lt;&#x2F;code&gt; เก็บเป็น &lt;code&gt;String Key (“DEP1”)&lt;&#x2F;code&gt; ไม่ใช่ Symbol Key&lt;&#x2F;li&gt;
&lt;li&gt;เลยหาไม่เจอ ทำให้ &lt;code&gt;serviceRegistry.get(...)&lt;&#x2F;code&gt; คืนค่า undefined&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;withiiaek-aichfangkchan-resolvedependencykey&quot;&gt;วิธีแก้: ใช้ฟังก์ชัน resolveDependencyKey(...)&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiiaek-aichfangkchan-resolvedependencykey&quot; aria-label=&quot;Anchor link for: withiiaek-aichfangkchan-resolvedependencykey&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เพื่อแก้ปัญหานี้ จึงเพิ่มฟังก์ชัน resolveDependencyKey(...) ขึ้นมา เพื่อให้แน่ใจว่า ทุกครั้งที่เรียก get(...) จะใช้ String Key ก่อนเสมอ:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createContainer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Services&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;serviceRegistry&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ServiceRegistry&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Services&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Container&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Services&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;resolveDependencyKey&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;DependencyKeyType&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Services&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dependencyKey&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;symbol&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;undefined&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-typeof z-ts&quot;&gt;typeof&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dependency&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-ts&quot;&gt;===&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;symbol&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;            &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ถ้าเป็น Symbol อยู่แล้ว ใช้ไปเลย&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;            &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dependencyKey&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;else&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;            &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ถ้าเป็น String ให้ Lookup จาก serviceRegistry ก่อน&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;            &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dependencyKey&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;serviceRegistry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dependencyKey&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;DependencyKeyType&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Services&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;dependencyKey&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;resolveDependencyKey&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dependencyKey&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;            &lt;span class=&quot;z-keyword z-control z-trycatch z-ts&quot;&gt;throw&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Error&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;No key found for dependency: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;toString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;phllaphthhlangaekaikh&quot;&gt;ผลลัพธ์หลังแก้ไข:&lt;a class=&quot;zola-anchor&quot; href=&quot;#phllaphthhlangaekaikh&quot; aria-label=&quot;Anchor link for: phllaphthhlangaekaikh&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;ไม่ว่า &lt;code&gt;container.get(...)&lt;&#x2F;code&gt; จะถูกเรียกด้วย String หรือ Symbol ก็ทำงานได้ถูกต้อง&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;serviceRegistry.get(...)&lt;&#x2F;code&gt; ไม่คืนค่า undefined อีกแล้ว&lt;&#x2F;li&gt;
&lt;li&gt;Unit Test ผ่าน ✅&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;btheriiyncchaakkaaraich-ai-model-gpt-4-o1&quot;&gt;บทเรียนจากการใช้ AI Model GPT-4 o1&lt;a class=&quot;zola-anchor&quot; href=&quot;#btheriiyncchaakkaaraich-ai-model-gpt-4-o1&quot; aria-label=&quot;Anchor link for: btheriiyncchaakkaaraich-ai-model-gpt-4-o1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;AI บางครั้งมั่นใจเกินไป
&lt;ul&gt;
&lt;li&gt;Model พยายามตอบว่า “มี serviceRegistry ซ้ำกัน” ถึง 10 ครั้ง ซึ่งเป็น สมมติฐานผิด&lt;&#x2F;li&gt;
&lt;li&gt;ต้องกดดัน AI ด้วยหลาย Prompt จนกว่ามันจะให้คำตอบที่ต่างออกไป&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;ต้อง Debug ข้อมูลเอง อย่าเชื่อ AI 100%
&lt;ul&gt;
&lt;li&gt;AI วิเคราะห์ปัญหาได้ดีในหลายกรณี แต่ก็พลาดง่ายๆ ในจุดที่ มนุษย์ คิดออกทันที&lt;&#x2F;li&gt;
&lt;li&gt;ใช้ AI เป็น เครื่องมือช่วยคิด ไม่ใช่ เครื่องมือคิดแทน&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;อย่าหลงประเด็นของ AI นานเกินไป
&lt;ul&gt;
&lt;li&gt;ถ้า AI ตอบแนวเดิมซ้ำๆ ลอง หยุดเชื่อ AI แล้วกลับมาไล่โค้ดเอง&lt;&#x2F;li&gt;
&lt;li&gt;ในเคสนี้ AI ย้ำเรื่อง Multiple Instances ทั้งที่ปัญหาจริงคือ Key Type Mismatch&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;srup&quot;&gt;สรุป&lt;a class=&quot;zola-anchor&quot; href=&quot;#srup&quot; aria-label=&quot;Anchor link for: srup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;การตั้งสมมติฐานควรตั้งอย่างใจเย็น ค่อยๆ ลดความเป็นไปได้ลง อย่าเชื่อ AI เยอะ แม้ว่าจะเป็น Model ที่ฉลาดๆ อย่าง o1 ก็ตาม
เพราะบริบทที่เข้าใจของ AI อาจจะไม่ตรงกับบริบทที่เราเข้าใจ และอาจจะทำให้เสียเวลาไปมากกว่าที่ควรจะเป็น&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าใครเคยเจอปัญหาแนวนี้ มาแชร์กันได้ในคอมเมนต์เลยครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ทำไม Microsoft เลือก Go ในการพัฒนา TypeScript Compiler แทนที่ของเดิม</title>
		<published>2025-03-15T00:00:00+00:00</published>
		<updated>2025-03-15T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/why-microsoft-choose-go-for-typescript-compiler/" type="text/html"/>
		<id>https://thadaw.com/posts/why-microsoft-choose-go-for-typescript-compiler/</id>
		<content type="html">&lt;p&gt;ตอนนี้เรื่อง TypeScript กำลังจะย้าย Compiler ไปใช้ Go แทน JavaScript กำลังเป็นประเด็นร้อน มีคนดังหลายคนในวงการออกมาวิเคราะห์กันเพียบ อย่าง Theo, Matt Pocock, และ Maximilian Schwarzmüller ซึ่งแน่นอนว่ามันต้องถึงเวลาของเพจ Thaitype แล้วแหละ แต่ว่าจะไม่ได้ดังอะไรขนาดนั้น 5555+ แต่เรื่องนี้น่าสนใจมากๆ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thamaimaimaich-rust-hruue-c&quot;&gt;ทำไมไม่ใช้ Rust หรือ C#?&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaimaimaich-rust-hruue-c&quot; aria-label=&quot;Anchor link for: thamaimaimaich-rust-hruue-c&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลังจากที่ Microsoft ออกมาประกาศเรื่องนี้ บอกเลยว่าเกิดเสียงวิพากษ์วิจารณ์สนั่น หลายคนถามว่า &quot;ทำไมไม่ใช้ Rust?&quot; หรือแม้แต่ &quot;C# ที่เป็นเรือธงของ Microsoft ทำไมไม่ใช้?&quot; เพราะ Rust เป็นภาษาที่กำลังมาแรงโดยเฉพาะในสาย Tooling และ C# ก็เป็นภาษาที่ Microsoft ภูมิใจนำเสนอมากที่สุดอยู่แล้ว การเลือก Go ทำให้หลายคนตั้งคำถามว่ามันเหมาะสมจริงหรือไม่?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thamaimt-ngepn-go&quot;&gt;ทำไมต้องเป็น Go?&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaimt-ngepn-go&quot; aria-label=&quot;Anchor link for: thamaimt-ngepn-go&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เรื่องนี้ Anders Hejlsberg ซึ่งเป็น Co-creator ของ TypeScript และ Technical Fellow ของ Microsoft ออกมาอธิบายเหตุผลหลายข้อที่ฟังแล้วต้องบอกว่า Make sense มากๆ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;white-check-mark-kaarphathnaaaebb-port-aimaich-rewrite&quot;&gt;✅ &lt;strong&gt;การพัฒนาแบบ Port ไม่ใช่ Rewrite&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#white-check-mark-kaarphathnaaaebb-port-aimaich-rewrite&quot; aria-label=&quot;Anchor link for: white-check-mark-kaarphathnaaaebb-port-aimaich-rewrite&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;TypeScript Compiler เดิมเขียนด้วย JavaScript และเป้าหมายหลักของการเปลี่ยนแปลงครั้งนี้คือการ &lt;strong&gt;Port&lt;&#x2F;strong&gt; ไปยังภาษาใหม่โดยยังคง &lt;strong&gt;โครงสร้างเดิม&lt;&#x2F;strong&gt; ให้มากที่สุด เพื่อลดความเสี่ยงในการเกิด Bug และเพื่อให้การเปลี่ยนแปลงราบรื่น ซึ่ง Go มี Syntax และ Paradigm ที่ใกล้เคียง JavaScript มากที่สุดในบรรดาภาษาที่พวกเขาพิจารณา&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;why-microsoft-choose-go-for-typescript-compiler&#x2F;typescript-go-compare-with-the-old.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;white-check-mark-go-r-ngrab-garbage-collection-chuengcchamepnt-typescript-compiler&quot;&gt;✅ &lt;strong&gt;Go รองรับ Garbage Collection ซึ่งจำเป็นต่อ TypeScript Compiler&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#white-check-mark-go-r-ngrab-garbage-collection-chuengcchamepnt-typescript-compiler&quot; aria-label=&quot;Anchor link for: white-check-mark-go-r-ngrab-garbage-collection-chuengcchamepnt-typescript-compiler&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ตัว Compiler ของ TypeScript ใช้ &lt;strong&gt;Cyclic Data Structures&lt;&#x2F;strong&gt; เยอะมาก (เช่น AST Nodes มีการอ้างอิง Parent-Child ไปมา) ซึ่งเป็นปัญหาใหญ่สำหรับ Rust เพราะ Rust ไม่มี Garbage Collection โดยธรรมชาติ ถ้าจะใช้ Rust จะต้องเปลี่ยน Data Structure ใหม่ทั้งหมด ซึ่งจะทำให้การ Port กลายเป็นการ Rewrite ไปเลย&lt;&#x2F;p&gt;
&lt;h3 id=&quot;white-check-mark-rust-aacchcchathamaiherwkwaa-aett-ngaichewlaanaanmaak&quot;&gt;✅ &lt;strong&gt;Rust อาจจะทำให้เร็วกว่า แต่ต้องใช้เวลานานมาก&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#white-check-mark-rust-aacchcchathamaiherwkwaa-aett-ngaichewlaanaanmaak&quot; aria-label=&quot;Anchor link for: white-check-mark-rust-aacchcchathamaiherwkwaa-aett-ngaichewlaanaanmaak&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Microsoft ทดลองเขียน Prototype ใน Rust, Go และ C# มาแล้ว ซึ่ง Rust มีประเด็นเรื่องการจัดการ Memory ที่ต้องใช้ Borrow Checker ซึ่งทำให้การแปลง Code ที่เดิมเขียนแบบ Dynamic ไปเป็น Rust ยุ่งยากขึ้นหลายเท่า ถ้าจะ Rewrite ใหม่ทั้งหมดใน Rust อาจใช้เวลา &quot;หลายปี&quot; กว่าที่จะทำให้มันเสถียร&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;หมายเหตุ:&lt;&#x2F;strong&gt;  ซึ่งปัญหาไม่ได้อยู่ที่ตัวภาษา แต่อยู่การออกแบบตามแบบฉบับของตัวภาษานั้นๆ แล้วทำให้หน้าตาโค๊ดเปลี่ยนไปเยอะ จนทำให้ย้ายปรับปรุงให้เสร็จใช้เวลานาน เพราะฉะนั้นวัตถุประสงค์ของการเปลี่ยน Compiler คือการทำให้การเปลี่ยนแปลงเป็นไปอย่างราบรื่นและรวดเร็วที่สุด โดยที่ยังคงความเสถียรเหมือนเดิม&lt;&#x2F;p&gt;
&lt;h3 id=&quot;white-check-mark-parallelism-shared-memory-concurrency&quot;&gt;✅ &lt;strong&gt;Parallelism &amp;amp; Shared Memory Concurrency&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#white-check-mark-parallelism-shared-memory-concurrency&quot; aria-label=&quot;Anchor link for: white-check-mark-parallelism-shared-memory-concurrency&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Go มี &lt;strong&gt;Goroutines&lt;&#x2F;strong&gt; และรองรับ &lt;strong&gt;Shared Memory Concurrency&lt;&#x2F;strong&gt; ทำให้สามารถรันการตรวจสอบ Type ได้หลาย Process พร้อมกัน ซึ่งช่วยให้ Compiler เร็วขึ้นแบบเห็นได้ชัด ในขณะที่ JavaScript ต้องใช้ Web Workers ซึ่งไม่สามารถแชร์ Memory ได้โดยตรง ทำให้การทำ Parallel Processing มี Overhead สูงกว่า&lt;&#x2F;p&gt;
&lt;h3 id=&quot;white-check-mark-community-phyaayaamtham-rust-typescript-compiler-maanaan-aetyangaimsamercch&quot;&gt;✅ &lt;strong&gt;Community พยายามทำ Rust TypeScript Compiler มานาน แต่ยังไม่สำเร็จ&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#white-check-mark-community-phyaayaamtham-rust-typescript-compiler-maanaan-aetyangaimsamercch&quot; aria-label=&quot;Anchor link for: white-check-mark-community-phyaayaamtham-rust-typescript-compiler-maanaan-aetyangaimsamercch&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ก่อนหน้านี้มีโปรเจคอย่าง &lt;strong&gt;stc (Speedy TypeScript Compiler)&lt;&#x2F;strong&gt; ที่พยายามเขียน TypeScript Compiler ใหม่ด้วย Rust แต่มันไม่เคยได้รับความนิยมในวงกว้าง และไม่ได้ไปถึงจุดที่สามารถแทน TSC ตัวปัจจุบันได้ การที่ Microsoft พยายาม Port ไป Rust อาจจะเจอปัญหาแบบเดียวกันและต้องเสียเวลาไปอีกหลายปี&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aenwkhidkaareluue-kekhruue-ngmuue-aihehmaaakabngaan&quot;&gt;แนวคิดการเลือกเครื่องมือให้เหมาะกับงาน&lt;a class=&quot;zola-anchor&quot; href=&quot;#aenwkhidkaareluue-kekhruue-ngmuue-aihehmaaakabngaan&quot; aria-label=&quot;Anchor link for: aenwkhidkaareluue-kekhruue-ngmuue-aihehmaaakabngaan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Anders Hejlsberg สรุปประเด็นนี้ไว้ได้ชัดเจนว่า &lt;strong&gt;&quot;นี่ไม่ใช่การเลือกภาษาที่ดีที่สุด แต่เป็นการเลือกภาษาที่เหมาะสมที่สุดกับโปรเจคนี้&quot;&lt;&#x2F;strong&gt; Microsoft ไม่ได้มองว่า Go ดีกว่า Rust ในทุกแง่ แต่เพราะ TypeScript Compiler เป็นโครงการที่ลงทุนมานานกว่า 10 ปี (คิดเป็น &lt;strong&gt;100 man-years of investment&lt;&#x2F;strong&gt;) การเลือกเครื่องมือที่ช่วยให้การเปลี่ยนแปลงเป็นไปอย่างราบรื่นและรวดเร็วที่สุดจึงเป็นเรื่องสำคัญกว่า&lt;&#x2F;p&gt;
&lt;h2 id=&quot;khwaamehnswntawkh-ngphm&quot;&gt;ความเห็นส่วนตัวของผม&lt;a class=&quot;zola-anchor&quot; href=&quot;#khwaamehnswntawkh-ngphm&quot; aria-label=&quot;Anchor link for: khwaamehnswntawkh-ngphm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลังจากศึกษาเรื่องนี้ ผมเห็นด้วยกับการตัดสินใจของทีม TypeScript มากๆ การเลือก Go มัน Make sense เพราะ:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;มันเร็วขึ้น 10x&lt;&#x2F;strong&gt; โดยไม่ต้อง Rewrite ใหม่ทั้งหมด&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;มันใช้เวลาพัฒนาได้เร็วกว่า Rust&lt;&#x2F;strong&gt; ซึ่งถ้าเลือก Rust อาจต้องใช้ &quot;หลายปี&quot; กว่าจะเสร็จ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Go มี Community ที่ใหญ่และ Performance ดี&lt;&#x2F;strong&gt; ไม่ได้เป็นภาษาแย่ๆ แต่อย่างใด&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;สิ่งที่ Matt Pocock พูดไว้ก็น่าสนใจ&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;We&#x27;re on version 5.8 now - so by the current cadence 7.0 will be around 33 months away.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;คืออีก &lt;strong&gt;3 ปี&lt;&#x2F;strong&gt; กว่า TypeScript 7.0 จะพร้อมใช้จริง ถ้าพวกเขาเลือก Rust ที่ต้อง Rewrite ใหม่ทั้งหมด เราอาจต้องรอไปอีกกี่ปีกัน?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;srupngaay-kaareluue-k-go-khuue-kaareluue-kthiidiithiisudsamhrabt-nnii&quot;&gt;&lt;strong&gt;สรุปง่ายๆ: การเลือก Go คือการเลือกที่ดีที่สุดสำหรับตอนนี้&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#srupngaay-kaareluue-k-go-khuue-kaareluue-kthiidiithiisudsamhrabt-nnii&quot; aria-label=&quot;Anchor link for: srupngaay-kaareluue-k-go-khuue-kaareluue-kthiidiithiisudsamhrabt-nnii&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;แม้มันจะไม่ใช่ภาษาที่ทุกคนอยากให้ใช้ แต่ถ้ามองจากมุมมองของวิศวกรรมซอฟต์แวร์ การเลือกเครื่องมือที่ &quot;เหมาะสมกับบริบทของโปรเจค&quot; สำคัญกว่า&lt;&#x2F;p&gt;
&lt;p&gt;สุดท้ายแล้ว ถ้ามันเร็วขึ้น 10 เท่า และยังคงความเสถียรเหมือนเดิม ใช้ได้โดยความสามารถเท่าเดิม แค่นี้ผมก้ Happy มากๆ แล้วนะละ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aang-ingtaang&quot;&gt;อ้างอิงต่างๆ&lt;a class=&quot;zola-anchor&quot; href=&quot;#aang-ingtaang&quot; aria-label=&quot;Anchor link for: aang-ingtaang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Official Post Annoucement byAnders : &quot;A 10x Faster TypeScript&quot;: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;devblogs.microsoft.com&#x2F;typescript&#x2F;typescript-native-port&#x2F;&quot;&gt;https:&#x2F;&#x2F;devblogs.microsoft.com&#x2F;typescript&#x2F;typescript-native-port&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Official Video Announcement by Anders: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=pNlq-EVld70&quot;&gt;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=pNlq-EVld70&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Anders Hejlsberg: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;microsoft&#x2F;typescript-go&#x2F;discussions&#x2F;411#discussioncomment-12476218&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;microsoft&#x2F;typescript-go&#x2F;discussions&#x2F;411#discussioncomment-12476218&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;TypeScript is being ported to Go | interview with Anders Hejlsberg: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=10qowKUW82U&quot;&gt;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=10qowKUW82U&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Maximilian Schwarzmüller : &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=tRiIcCOhN6A&quot;&gt;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=tRiIcCOhN6A&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Theo: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=3-W95H5_lX0&quot;&gt;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=3-W95H5_lX0&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Matt Pocock: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.totaltypescript.com&#x2F;typescript-announces-go-rewrite&quot;&gt;https:&#x2F;&#x2F;www.totaltypescript.com&#x2F;typescript-announces-go-rewrite&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ใครเฝ้ายาม? แล้วใครเฝ้ายามของยาม?</title>
		<published>2025-03-14T00:00:00+00:00</published>
		<updated>2025-03-14T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/who-watches-the-watchers/" type="text/html"/>
		<id>https://thadaw.com/posts/who-watches-the-watchers/</id>
		<content type="html">&lt;p&gt;ช่วงนี้กำลังออกแบบระบบ Security อยู่ ตอนแรกคิดว่าไม่น่าจะยาก แค่ต้อง &lt;strong&gt;Encrypt ข้อมูลใน Vault&lt;&#x2F;strong&gt; ก็พอ แต่พอเริ่มทำจริงๆ เจอปัญหาคลาสสิกขึ้นมาเลย&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ถ้าผม Encrypt Vault ผมต้องเก็บ &lt;strong&gt;Key&lt;&#x2F;strong&gt; ไว้ที่ไหน?&lt;&#x2F;li&gt;
&lt;li&gt;ถ้าผมมีที่เก็บ Key ผมต้อง Encrypt มันมั้ย? แล้ว Key ของตัวที่เก็บ Key ล่ะ?&lt;&#x2F;li&gt;
&lt;li&gt;ถ้าผมมี Key ของตัวที่เก็บ Key แล้ว ผมจะเก็บมันที่ไหน?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;วนลูปไปเรื่อยๆ แบบไม่มีจุดสิ้นสุด&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;who-watches-the-watchers&#x2F;who-watches-the-watcher.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;payhaa-aikhrefaayaam&quot;&gt;ปัญหา &quot;ใครเฝ้ายาม?&quot;&lt;a class=&quot;zola-anchor&quot; href=&quot;#payhaa-aikhrefaayaam&quot; aria-label=&quot;Anchor link for: payhaa-aikhrefaayaam&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เรื่องนี้ทำให้นึกถึงตอนเรียน Computer Security สมัยมหาลัย อาจารย์ชอบยกตัวอย่างว่า&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ถ้ามี &lt;strong&gt;ทรัพย์สิน (Vault)&lt;&#x2F;strong&gt; แล้วเราจ้าง &lt;strong&gt;ยาม&lt;&#x2F;strong&gt; มาเฝ้า&lt;&#x2F;li&gt;
&lt;li&gt;แล้วเราต้องให้ &lt;strong&gt;ยามอีกคน&lt;&#x2F;strong&gt; มาเฝ้ายาม&lt;&#x2F;li&gt;
&lt;li&gt;แล้วต้องมี &lt;strong&gt;ยามอีกคน&lt;&#x2F;strong&gt; เฝ้ายามของยาม&lt;&#x2F;li&gt;
&lt;li&gt;แล้วก็ต้องมี &lt;strong&gt;ยามอีกคน&lt;&#x2F;strong&gt; เฝ้ายามของยามของยาม&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;แบบนี้ไปเรื่อยๆ ไม่มีที่สิ้นสุด แล้วสุดท้าย...ใครจะเฝ้าคนสุดท้าย?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;eraacchaaekpayhaaniiyangaing&quot;&gt;เราจะแก้ปัญหานี้ยังไง?&lt;a class=&quot;zola-anchor&quot; href=&quot;#eraacchaaekpayhaaniiyangaing&quot; aria-label=&quot;Anchor link for: eraacchaaekpayhaaniiyangaing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ใน Security เรามีหลายวิธีแก้ปัญหานี้ ขึ้นอยู่กับบริบทของระบบที่ออกแบบ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-aich-root-of-trust&quot;&gt;1. &lt;strong&gt;ใช้ Root of Trust&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-aich-root-of-trust&quot; aria-label=&quot;Anchor link for: 1-aich-root-of-trust&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;ปัญหาจะจบลงเมื่อเรากำหนด &quot;ต้นทางที่เชื่อถือได้&quot; หรือ &lt;strong&gt;Root of Trust&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ตัวอย่างเช่น &lt;strong&gt;HTTPS และ SSL&#x2F;TLS Certificates&lt;&#x2F;strong&gt; ที่มี Root Certificate Authority (CA) เป็นผู้ที่เราเชื่อถืออยู่แล้ว ทำให้ไม่มีการวนลูปของความเชื่อถือ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;2-aich-hardware-security-module-hsm&quot;&gt;2. &lt;strong&gt;ใช้ Hardware Security Module (HSM)&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-aich-hardware-security-module-hsm&quot; aria-label=&quot;Anchor link for: 2-aich-hardware-security-module-hsm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;แทนที่จะเก็บ Key ไว้ในซอฟต์แวร์ที่ต้อง Encrypt ซ้ำไปมา เราใช้ &lt;strong&gt;Hardware Security Module (HSM)&lt;&#x2F;strong&gt; ที่ออกแบบให้เก็บ Key อย่างปลอดภัย&lt;&#x2F;li&gt;
&lt;li&gt;HSM มีฟังก์ชันที่ป้องกันการเข้าถึงโดยไม่ได้รับอนุญาต และทำให้เราไม่ต้อง Encrypt ซ้ำไปซ้ำมา อย่างเช่น Azure Key Vault ก็มีบริการที่เป็น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;key-vault&#x2F;managed-hsm&#x2F;overview?wt.mc_id=MVP_396631&quot;&gt;Managed HSM Service&lt;&#x2F;a&gt; ด้วยเหมือนกัน ถ้าเราโฟกัสเรื่อง Security ที่มากขึ้นก็ลองไปดูเพิ่มได้&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;3-aich-multi-party-approval-split-knowledge&quot;&gt;3. &lt;strong&gt;ใช้ Multi-Party Approval &amp;amp; Split Knowledge&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-aich-multi-party-approval-split-knowledge&quot; aria-label=&quot;Anchor link for: 3-aich-multi-party-approval-split-knowledge&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;ระบบสำคัญบางอย่างอาจใช้แนวทางให้ &lt;strong&gt;หลายคนต้องอนุมัติ&lt;&#x2F;strong&gt; ก่อนเข้าถึงข้อมูล&lt;&#x2F;li&gt;
&lt;li&gt;ตัวอย่างเช่น &lt;strong&gt;ในธนาคาร การโอนเงินที่เกินจำนวนหนึ่งจะต้องได้รับการอนุมัติจากผู้จัดการ 2 คน&lt;&#x2F;strong&gt; ก่อนที่เงินจะถูกโอนจริง&lt;&#x2F;li&gt;
&lt;li&gt;หรือในระบบ Security บางระบบ เราใช้ &lt;strong&gt;Shamir’s Secret Sharing&lt;&#x2F;strong&gt; เพื่อแบ่ง Key ออกเป็นหลายส่วน แล้วให้แต่ละส่วนอยู่กับคนละฝ่าย ทำให้ไม่มีใครสามารถใช้ Key ได้โดยลำพัง ซึ่ง HashiCorp Vault เองก็ใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;developer.hashicorp.com&#x2F;vault&#x2F;docs&#x2F;concepts&#x2F;seal#shamir-seals&quot;&gt;Shamir&#x27;s Secret Sharing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;4-aich-zero-trust-architecture&quot;&gt;4. &lt;strong&gt;ใช้ Zero Trust Architecture&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-aich-zero-trust-architecture&quot; aria-label=&quot;Anchor link for: 4-aich-zero-trust-architecture&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;แทนที่จะสร้างความเชื่อถือเป็นชั้นๆ ไปเรื่อยๆ เราใช้หลัก &lt;strong&gt;“เชื่อถือเป็นศูนย์” (Never Trust, Always Verify)&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ทุกครั้งที่มีการเข้าถึงข้อมูลสำคัญ ต้องมีการตรวจสอบสิทธิ์ใหม่เสมอ ไม่ว่าจะเป็น Admin หรือ System Process ก็ตาม&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;5-aich-immutable-logging-auditing&quot;&gt;5. &lt;strong&gt;ใช้ Immutable Logging &amp;amp; Auditing&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#5-aich-immutable-logging-auditing&quot; aria-label=&quot;Anchor link for: 5-aich-immutable-logging-auditing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;แทนที่จะมีคนเฝ้ากันไปเรื่อยๆ เราใช้ &lt;strong&gt;ระบบตรวจสอบย้อนหลังที่แก้ไขไม่ได้&lt;&#x2F;strong&gt; เช่น &lt;strong&gt;Blockchain-based Audit Logs หรือ SIEM (Security Information and Event Management)&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ตัวอย่างเช่น &lt;strong&gt;ในระบบ Blockchain การแก้ไขย้อนหลังเป็นไปไม่ได้ เพราะทุกธุรกรรมต้องได้รับฉันทามติจากโหนดที่เกี่ยวข้อง&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;aenwkhidkaar-kaebbrabbkhwaampl-dphay&quot;&gt;แนวคิดการออกแบบระบบความปลอดภัย&lt;a class=&quot;zola-anchor&quot; href=&quot;#aenwkhidkaar-kaebbrabbkhwaampl-dphay&quot; aria-label=&quot;Anchor link for: aenwkhidkaar-kaebbrabbkhwaampl-dphay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;การเพิ่มระบความปลอดภัยของ Security &lt;strong&gt;ไม่ใช่แค่การเพิ่ม Layer ไปเรื่อยๆ&lt;&#x2F;strong&gt; แต่ควรออกแบบให้ถูกต้อง&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ถ้าเราต้องเฝ้ากันเป็นชั้นๆ โดยไม่มีจุดสิ้นสุด แสดงว่ามีบางอย่างผิดพลาดในการออกแบบ&lt;&#x2F;li&gt;
&lt;li&gt;การสร้าง Layer ที่ซับซ้อนเกินไป อาจทำให้ระบบ &lt;strong&gt;ยากต่อการดูแล และยังมีช่องโหว่จากความผิดพลาดของมนุษย์&lt;&#x2F;strong&gt; เช่น
&lt;ul&gt;
&lt;li&gt;การตั้งค่าผิดพลาด&lt;&#x2F;li&gt;
&lt;li&gt;การจัดการ Key ที่ยุ่งยาก&lt;&#x2F;li&gt;
&lt;li&gt;การเปิดสิทธิ์มากเกินไปเพื่อ &quot;ความสะดวก&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Security ที่เหมาะสมคือการ &lt;strong&gt;กำหนด Root of Trust และใช้หลัก Zero Trust เพื่อไม่ต้องพึ่ง Layer ที่ซับซ้อนเกินไป&lt;&#x2F;strong&gt; และขึ้นอยู่กับความสามารถยอมรับและความเสี่ยงของ Security ที่รับได้&lt;&#x2F;p&gt;
&lt;h2 id=&quot;btheriiyncchaakeruue-ngnii&quot;&gt;บทเรียนจากเรื่องนี้&lt;a class=&quot;zola-anchor&quot; href=&quot;#btheriiyncchaakeruue-ngnii&quot; aria-label=&quot;Anchor link for: btheriiyncchaakeruue-ngnii&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Security ที่เหมาะสมต้องมีจุดเริ่มต้นที่ชัดเจน&lt;&#x2F;strong&gt; เช่น Root of Trust หรือ Hardware Security Module&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Security ควรถูกออกแบบให้เรียบง่าย&lt;&#x2F;strong&gt; ไม่ใช่แค่เพิ่ม Layer ป้องกันที่ซับซ้อน&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Automation &amp;amp; Monitoring สำคัญกว่าการให้คนเฝ้ากันไปเรื่อยๆ&lt;&#x2F;strong&gt; ควรใช้ Immutable Logs และ AI-Based Security Monitoring&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ความผิดพลาดของมนุษย์คือจุดอ่อนที่ใหญ่ที่สุดของ Security&lt;&#x2F;strong&gt; ดังนั้น การออกแบบที่ลดการพึ่งพามนุษย์ให้มากที่สุดจะช่วยลดความเสี่ยงได้&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;sudthaay-security-thiiehmaaasmsamhrabphm-kkhuue&quot;&gt;สุดท้าย Security ที่เหมาะสมสำหรับผม ก็คือ&lt;a class=&quot;zola-anchor&quot; href=&quot;#sudthaay-security-thiiehmaaasmsamhrabphm-kkhuue&quot; aria-label=&quot;Anchor link for: sudthaay-security-thiiehmaaasmsamhrabphm-kkhuue&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;การออกแบบที่เหมาะสม ความสามารถในยอมรับจากการประเมินความเสี่ยง ทรัพยากรที่ต้องเสียไปกับการที่ทำให้ระบบแข็งแรงขึ้น มันคุ้มค่ากับของที่ต้องปกป้องมั้ย และการลดการใช้มนุษย์บางขั้นตอน อาจจะนำ AI หรือ ระบบคอมพิวเตอร์เข้ามาช่วยตรวจด้วยก็ได้&lt;&#x2F;p&gt;
&lt;p&gt;ก่อนจะจากกันประเด็นเรื่อง Security เป็นประเด็นที่ยากมากสำหรับผมที่เขียนให้แล้วไม่ถูกวิพากษ์วิจารณ์ ถ้าสิ่งที่ผมเขียนไม่ถูกต้องอย่างไร อยากให้หยิบขึ้นมาประเด็นที่ถกเถียงกันด้วยเหตุและผล ผมเป็นเพียงคนจุดประเด็นเรื่องขึ้นมาพูดคุย ถ้าจุดไหนผมกล่าวผิดไป จะหยิบนำไปปรับปรุงต่อไป&lt;&#x2F;p&gt;
&lt;p&gt;ขอบคุณที่อ่านและติดตามนะครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ออกแบบการใช้ API Key อย่างปลอดภัย โดยใช้ Azure Table เป็นกรณีศึกษา</title>
		<published>2025-01-21T00:00:00+00:00</published>
		<updated>2025-01-21T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/secure-api-access/" type="text/html"/>
		<id>https://thadaw.com/posts/secure-api-access/</id>
		<content type="html">&lt;p&gt;วันก่อนไปนั่งแกะ Authentication ของ Azure table มาเลย ว่าเวลาที่เค้ายืนยันตัวตน ผ่าน API เค้าทำยังไง แล้วก็เจอว่าเค้าใช้ เค้าใช้ Signature คู่กับ Access Key และบังเอิญโพสของ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;alexxubyte&quot;&gt;Alex Xu ใน X&lt;&#x2F;a&gt; ว่าด้วยเรื่องของ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;alexxubyte&#x2F;status&#x2F;1881034986561982952?t=u2PahKOS7wvncXHEorTJzQ&amp;amp;s=19&quot;&gt;&quot;How do we design effective and safe APIs?&quot;&lt;&#x2F;a&gt; ซึ่งอธิบายเรื่องนึงที่ผมสังเกตุเห็นก็คือ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; class=&quot;language-diff z-code&quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span class=&quot;z-source z-diff&quot;&gt;Secure Access API
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-diff&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-diff&quot;&gt;&lt;span class=&quot;z-markup z-deleted z-diff&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-deleted z-diff&quot;&gt;-&lt;&#x2F;span&gt; GET &#x2F;api&#x2F;private
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-diff&quot;&gt;&lt;span class=&quot;z-markup z-deleted z-diff&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-deleted z-diff&quot;&gt;-&lt;&#x2F;span&gt; Header: X-API-KEY: &amp;lt;API_KEY&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-diff&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-diff&quot;&gt;&lt;span class=&quot;z-markup z-inserted z-diff&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-inserted z-diff&quot;&gt;+&lt;&#x2F;span&gt; Header: X-API-KEY: &amp;lt;API_KEY&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-diff&quot;&gt;&lt;span class=&quot;z-markup z-inserted z-diff&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-inserted z-diff&quot;&gt;+&lt;&#x2F;span&gt;         X-EXPIRY: &amp;lt;API_KEY&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-diff&quot;&gt;&lt;span class=&quot;z-markup z-inserted z-diff&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-inserted z-diff&quot;&gt;+&lt;&#x2F;span&gt;         X-REQUEST-SIGNATURE: hmac(URL + Query + Expiry + Body)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ที่นี้เรามาดูกันดีกว่าว่าทำไม  &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;alexxubyte&quot;&gt;Alex Xu&lt;&#x2F;a&gt; ถึงแนะนำออกแบบไม่ให้ส่ง API KEY ไปตรงๆ แบบโจ่งแจ้งแบบนั้น&lt;&#x2F;p&gt;
&lt;p&gt;ยกตัวอย่าง เวลาที่เราพัฒนาระบบระบบนึง เช่น E-commerce API อย่างเรามี API สำหรับการสร้างออเดอร์หรือดูรายละเอียดสินค้า หลายคนอาจเลือกใช้ API Key ในการยืนยันตัวตน เพราะมันใช้งานง่าย แค่ใส่ API Key ลงใน header เช่น &lt;code&gt;X-API-KEY&lt;&#x2F;code&gt; ระบบก็ทำงานได้ทันที แต่การใช้แค่ API Key อย่างเดียวกลับมีความเสี่ยงที่ในหลายๆ มิติ เราไปดูกัน&lt;&#x2F;p&gt;
&lt;h2 id=&quot;taw-yaangpayhaaain-api&quot;&gt;ตัวอย่างปัญหาใน API&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangpayhaaain-api&quot; aria-label=&quot;Anchor link for: taw-yaangpayhaaain-api&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;สมมติเราออกแบบ API สำหรับร้านค้าออนไลน์ โดย API มีฟังก์ชันสำคัญ เช่น:&lt;&#x2F;p&gt;
&lt;p&gt;สร้างคำสั่งซื้อ:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;POST &#x2F;api&#x2F;orders
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Header: X-API-KEY: &amp;lt;API_KEY&amp;gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Body: { &amp;quot;productId&amp;quot;: 123, &amp;quot;quantity&amp;quot;: 1 }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;หาก API Key รั่วไหล ผู้ไม่หวังดีอาจสร้างคำสั่งซื้อปลอมในระบบ ส่งผลให้สต็อกสินค้าและการจัดการคำสั่งซื้อผิดพลาด&lt;&#x2F;p&gt;
&lt;h3 id=&quot;payhaakh-ngkaaraichaekh-api-key&quot;&gt;ปัญหาของการใช้แค่ API Key&lt;a class=&quot;zola-anchor&quot; href=&quot;#payhaakh-ngkaaraichaekh-api-key&quot; aria-label=&quot;Anchor link for: payhaakh-ngkaaraichaekh-api-key&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;API Key สามารถถูกขโมยได้&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าเราส่ง API Key ผ่านอินเทอร์เน็ตโดยไม่มีการเข้ารหัส เช่น ใช้ HTTP แทน HTTPS ผู้ไม่หวังดีสามารถดักจับ (sniffing) API Key ของเราไปใช้งานต่อได้ทันที ซึ่งถ้าระบบของเราไม่มีวิธีป้องกันเพิ่มเติม มันก็เหมือนเราให้ &quot;กุญแจบ้าน&quot; กับคนอื่นไปเลย หรือบางครั้งเราใส่ API KEY ไปที่ Query Params โดยตรงซึ่งเราอาจจะถูกดักจับได้จากพวก Router หรือพวก ISP ได้ครับ เช่น &lt;code&gt;GET &#x2F;api&#x2F;orders?key=XXXX&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Replay Attacks&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;การใช้ API Key อย่างเดียว ทำให้ผู้โจมตีสามารถเอา Request เดิมๆ ของเรามาใช้อีกครั้งได้ เพราะ API Key ไม่ได้ผูกกับข้อมูลเฉพาะของ Request นั้นๆ เช่น เวลา (timestamp) หรือรายละเอียดของ Request&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ตรวจสอบความถูกต้องไม่ได้&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;API Key ไม่สามารถบอกได้ว่า ข้อมูลใน Request นั้นถูกแก้ไขระหว่างทางหรือเปล่า เพราะมันไม่มีการลงนาม (signature) เพื่อยืนยันความถูกต้อง&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;thamaimt-ngaich-signature&quot;&gt;ทำไมต้องใช้ Signature?&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaimt-ngaich-signature&quot; aria-label=&quot;Anchor link for: thamaimt-ngaich-signature&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Signature&lt;&#x2F;strong&gt; คือ &quot;ลายเซ็นดิจิทัล&quot; ที่สร้างจากข้อมูลที่เราต้องการ เช่น ใน Request เราอาจจะใช้ URL, เวลา, และ Request Body โดยเข้ารหัส (hashed) ด้วย &lt;strong&gt;Secret Key&lt;&#x2F;strong&gt; ซึ่งมันช่วยให้การยืนยันตัวตนปลอดภัยขึ้นมาก&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ป้องกันการปลอม Request&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;เพราะ Signature ถูกสร้างขึ้นจากข้อมูลเฉพาะของ Request  เช่น URL และเวลา หากไม่มี Secret Key ก็ไม่มีทางสร้าง Signature ที่ถูกต้องได้&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ป้องกัน Replay Attacks&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;การใช้ Timestamp (เช่น &lt;code&gt;x-ms-date&lt;&#x2F;code&gt;) ช่วยให้ Signature มีอายุจำกัด ถ้า Request ถูกส่งซ้ำหลังเวลาที่กำหนด  Request นั้นจะถูกปฏิเสธทันที&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;มั่นใจได้ว่าข้อมูลไม่ถูกแก้ไข&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Signature ยืนยันได้ว่าข้อมูลใน Request ไม่ได้ถูกดัดแปลงระหว่างทาง เพราะ Signature จะเปลี่ยนทันทีหากข้อมูลเปลี่ยน&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;kaaraich-signature-ephuue-aekpayhaa&quot;&gt;การใช้ Signature เพื่อแก้ปัญหา&lt;a class=&quot;zola-anchor&quot; href=&quot;#kaaraich-signature-ephuue-aekpayhaa&quot; aria-label=&quot;Anchor link for: kaaraich-signature-ephuue-aekpayhaa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;การเพิ่ม Signature ในการยืนยันตัวตนช่วยให้ Request แต่ละ Request ปลอดภัยยิ่งขึ้น ตัวอย่างเช่น ในระบบ E-commerce เราอาจออกแบบให้ Request  POST หรือ PUT ต้องมี Signature แบบนี้ ในตัวอย่างข้างล่างเป็นแค่แนวคิด Algorithm ซึ่งสามารถนำไปประยุกต์ใช้ได้ทุกภาษา:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;สร้างข้อความที่ต้องการจะ Sign รวมข้อมูลสำคัญใน Request  เช่น HTTP Method, URL, Timestamp และ API Key อย่างเช่น:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;stringToSign&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;POST&lt;span class=&quot;z-constant z-character z-escape z-ts&quot;&gt;\n&lt;&#x2F;span&gt;&#x2F;api&#x2F;orders&lt;span class=&quot;z-constant z-character z-escape z-ts&quot;&gt;\n&lt;&#x2F;span&gt;x-timestamp:2025-01-21T10:00:00Z&lt;span class=&quot;z-constant z-character z-escape z-ts&quot;&gt;\n&lt;&#x2F;span&gt;productId=123&amp;amp;quantity=1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;สร้าง Signatureใช้ HMAC-SHA256 เข้ารหัส String to Sign ด้วย Secret Key (โดยที่ HMAC คือการเข้ารหัส Signature ด้วย Algorithm อะไรก็ได้ที่เป็น Hash function พร้อมกับ Secret:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;signature&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;hmac&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;sha-256&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;stringToSign&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;secretKey&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;แนบ Signature ใน Request ส่ง Signature และ Timestamp ไปใน header:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;POST &#x2F;api&#x2F;orders
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Headers:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;X-API-KEY: &amp;lt;API_KEY&amp;gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;X-TIMESTAMP: 2025-01-21T10:00:00Z
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;X-SIGNATURE: &amp;lt;Signature&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ตรวจสอบ Signature ที่ฝั่งเซิร์ฟเวอร์ เซิร์ฟเวอร์จะสร้าง Signature ใหม่จาก Request ที่ได้รับ และตรวจสอบว่าตรงกับ Signature ที่ผู้ใช้ส่งมาหรือไม่ หากไม่ตรงกัน  Request จะถูกปฏิเสธทันที แสดงว่าเราควรเก็บ Secret ให้ดี ดังนั้นเราไม่ควร Sign พวก Signature ที่ Browser เพราะเราสามารถเปิด source code เพื่อดู Secret ได้&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;taw-yaangcchaak-azure-storage-table&quot;&gt;ตัวอย่างจาก Azure Storage Table&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangcchaak-azure-storage-table&quot; aria-label=&quot;Anchor link for: taw-yaangcchaak-azure-storage-table&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ที่นี้เรามาดูตัวอย่างของจริงกันบ้าง ใน Azure มีบริการนึงชื่อว่า Azure Table ซึ่งเป็น Serverless NoSQL Database ที่เป็นแบบ Table  ซึ่งเราสามารถเข้าถึง Data ของ Azure Table ได้&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่ง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;storage&#x2F;common&#x2F;authorize-data-access?tabs=tables&quot;&gt;Azure Table สามารถยืนยันตัวตนและรับรองสิทธิของ Data ได้หลายวิธี&lt;&#x2F;a&gt;) ซึ่ง &lt;strong&gt;Shared Key Authorization&lt;&#x2F;strong&gt; ก็เป็นวิธีการรับรองสิทธิ์ที่ใช้สำหรับการเข้าถึงข้อมูลใน &lt;strong&gt;Azure Storage&lt;&#x2F;strong&gt; ซึ่งรองรับบริการต่าง ๆ เช่น Blobs, Files, Queues และ Tables โดยการทำงานจะเป็นดังนี้:&lt;&#x2F;p&gt;
&lt;p&gt;เมื่อไคลเอนต์ (Client) ต้องการส่งคำขอ (Request) ไปยัง Azure Storage จะต้องแนบ &lt;strong&gt;Header&lt;&#x2F;strong&gt; ที่ถูกเซ็นด้วย &lt;strong&gt;Storage Account Access Key&lt;&#x2F;strong&gt; ซึ่งเป็นคีย์ลับสำหรับการเข้าถึงบัญชีเก็บข้อมูล
ซึ่งเราสามารถดูวิธีการ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;rest&#x2F;api&#x2F;storageservices&#x2F;authorize-with-shared-key&#x2F;&quot;&gt;Authorize with Shared Key&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;p&gt;ซึ่งใน Azure Table เราสามารถเลือกใช้ได้ 2 บริการ ก็คือ Azure Storage Account ซึ่งจะมีบริการ Table อยู่ข้างใน หรือจะใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;cosmos-db&#x2F;table&#x2F;introduction&quot;&gt;Azure Cosmos Table&lt;&#x2F;a&gt; ก็ได้เหมือนกัน&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;&lt;h2 id=&quot;taw-yaangkaaraichngaancchringcchaak-azure-table&quot;&gt;ตัวอย่างการใช้งานจริงจาก Azure Table&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangkaaraichngaancchringcchaak-azure-table&quot; aria-label=&quot;Anchor link for: taw-yaangkaaraichngaancchringcchaak-azure-table&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ในตัวอย่างผมแกะมาจาก Scheme ที่เป็น  &lt;strong&gt;Shared Key Lite&lt;&#x2F;strong&gt; ซึ่งเป็นวิธีการ Authentication ไปยัง Azure Table วิธีการนึง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;rest&#x2F;api&#x2F;storageservices&#x2F;authorize-with-shared-key&quot;&gt;&lt;strong&gt;Shared Key authorization&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt; ซึ่งผมได้แกะมาจาก Source Code ของ Azure Table Client ที่อยู่ใน npm &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.npmjs.com&#x2F;package&#x2F;@azure&#x2F;data-tables&quot;&gt;@azure&#x2F;data-tables@13.3.0&lt;&#x2F;a&gt; โดยตัวอย่างข้างล่างผมหยิบมาจากตัวอย่างโค๊ด &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Azure&#x2F;azure-sdk-for-js&#x2F;blob&#x2F;%40azure&#x2F;data-tables_13.3.0&#x2F;sdk&#x2F;tables&#x2F;data-tables&#x2F;src&#x2F;tablesNamedCredentialPolicy.ts#L37-L64&quot;&gt;tablesNamedCredentialPolicy.ts&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Azure Table Storage ใช้การยืนยันตัวตนแบบ &lt;strong&gt;Shared Key Lite&lt;&#x2F;strong&gt; โดยต้องสร้าง Signature จากข้อมูลใน Request  เช่น:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;x-ms-date&lt;&#x2F;code&gt; (วันที่ใน Request )&lt;&#x2F;li&gt;
&lt;li&gt;Canonicalized Resource (ข้อมูลทรัพยากร เช่น ชื่อตาราง)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ตัวอย่างโค้ดสร้าง Authorization Header:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;stringToSign&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dateHeader&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-ts&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;getCanonicalizedResourceString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;credential&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;signature&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;computeHMACSHA256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;stringToSign&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;credential&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;authorizationHeader&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;SharedKeyLite &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;credential&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;:&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;signature&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;withiikaarthamngaan&quot;&gt;วิธีการทำงาน:&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiikaarthamngaan&quot; aria-label=&quot;Anchor link for: withiikaarthamngaan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;สร้าง String to Sign&lt;&#x2F;strong&gt; รวมข้อมูลสำคัญ เช่น วันที่และข้อมูลทรัพยากร&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;สร้าง Signature&lt;&#x2F;strong&gt; ใช้ HMAC-SHA256 เพื่อเข้ารหัส String to Sign ด้วย Secret Key&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ตรวจสอบ Signature&lt;&#x2F;strong&gt; ฝั่งเซิร์ฟเวอร์จะสร้าง Signature ใหม่จากข้อมูลใน Request ที่ได้รับ แล้วเปรียบเทียบกับ Signature ที่ส่งมาด้วย&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;p&gt;ถ้าสังเกตุดีๆ จะเห็นว่า ตัวอย่างเรื่อง Signature ของ API Key ที่ยกตัวอย่างมา รวมถึงของทาง   &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;alexxubyte&quot;&gt;Alex Xu&lt;&#x2F;a&gt; และ  Shared Key Authorization ของ Azure มีความต่างกันของ Header ที่จะส่งอยู่&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;โดยทั่วไปแล้ว API Key สามารถให้เห็นได้ เพราะเราอาจจะใช้หลาย Token แล้วจำนวนต้องบอกไปยัง Server ว่าเราใช้ API Key ไหน&lt;&#x2F;li&gt;
&lt;li&gt;แต่ในกรณีของ Azure เจ้า API Key หรือก็คือ Shared Key Authorization นั้น เป็นเหมือน Master Key ก็คือถ้าหลุดไป สามารถเข้าถึงได้เยอะมาก แต่มีได้แค่ Key เดียว ซึ่งฝั่ง Server จะรู้อยู่แล้วว่าต้องใช้ Key อะไรเอาไป Sign เพื่อเปรียบเทียบกัน&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ดังนั้นเลือก และตัดสินใจวิธีการ Authentication ด้วยความเข้าใจ ขอบเขตของความปลอดภัย&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;&lt;h2 id=&quot;thamaim-microsoft-aenanamaihelikaich-shared-key-authorization-kab-azure-storage&quot;&gt;ทำไม Microsoft แนะนำให้เลิกใช้ Shared Key Authorization กับ Azure Storage?&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaim-microsoft-aenanamaihelikaich-shared-key-authorization-kab-azure-storage&quot; aria-label=&quot;Anchor link for: thamaim-microsoft-aenanamaihelikaich-shared-key-authorization-kab-azure-storage&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;อย่างไรก็ตาม ทาง Azure แนะนำให้เรา &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;storage&#x2F;common&#x2F;shared-key-authorization-prevent&quot;&gt;ปิดการใช้งาน Shared Key authorization&lt;&#x2F;a&gt;เพราะมันไม่เหมาะกับบริบทนี้ แต่ไม่ได้หมายความว่าการ Sign Signature แบบนี้จะไม่ปลอดภัยซะทีเดียว มันอยู่ที่เรารับระดับของความปลอดภัยได้มากน้อนแค่ไหน&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ทำไมการใช้ Shared Key Authorization ถึงต้องระมัดระวัง?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ความสำคัญของ Access Key:&lt;&#x2F;strong&gt; คีย์นี้เป็นเหมือนกุญแจหลัก (Master Key) ของบัญชีเก็บข้อมูล ถ้าคีย์นี้ตกไปอยู่ในมือคนอื่น ไม่ว่าจะด้วยความผิดพลาดหรือการโจมตีทางไซเบอร์ ผู้ที่ได้คีย์ไปจะสามารถเข้าถึงข้อมูลทุกอย่างในบัญชีของคุณได้ รวมถึงการลบหรือแก้ไขข้อมูล&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ไม่มีการควบคุมแบบละเอียด (Limited Control&lt;&#x2F;strong&gt;): การใช้ Shared Key ไม่สามารถกำหนดสิทธิ์เฉพาะเจาะจงให้ผู้ใช้แต่ละคนได้ เช่น การอนุญาตให้บางคนอ่านข้อมูลอย่างเดียว หรือให้สิทธิ์เฉพาะบางโฟลเดอร์&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;srup&quot;&gt;สรุป&lt;a class=&quot;zola-anchor&quot; href=&quot;#srup&quot; aria-label=&quot;Anchor link for: srup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;การใช้แค่ API Key อาจทำให้ระบบของเราถูกเจาะง่าย เช่น ถ้า API Key รั่วไหลไป ระบบของเราก็จะโดนใช้แบบไม่จำกัด การเพิ่ม Signature ช่วยให้ Request แต่ละ Request มีความเฉพาะตัว ป้องกันการปลอมแปลง ลดความเสี่ยงจาก Replay Attacks และยืนยันได้ว่า Request มาจากแหล่งที่ถูกต้อง เหมือนกับที่ Azure Table Storage ใช้วิธีนี้เพื่อความปลอดภัยของข้อมูล&lt;&#x2F;p&gt;
&lt;p&gt;ถามว่า ทำไมผมถึงยกตัวอย่างของ Azure Table เพราะ Shared Key Authorization คล้ายกับการใช้ &lt;strong&gt;API Key&lt;&#x2F;strong&gt; โดยเซ็นข้อความ (Sign Signature) ด้วย &lt;strong&gt;HMAC (Hash-based Message Authentication Code)&lt;&#x2F;strong&gt; ซึ่งมีการเข้ารหัสที่แข็งแรงอยู่แล้ว ถ้าคุณไม่ได้กังวลเรื่องความปลอดภัยมากนัก หรือเป็นระบบที่ไม่ได้เก็บข้อมูลสำคัญ Shared Key ก็อาจจะยังเป็นตัวเลือกที่เหมาะสมอยู่นะ&lt;&#x2F;p&gt;
&lt;p&gt;ดังนั้นเวลาเราออกแบบ เราควรจะเลือกวิธีการออกแบบให้เหมาะสมกับสถานการณ์นั้นๆ และการ Secure API Token ด้วย Signature ยังตอบโจทย์ในหลายสถานการณ์อยู่ครับ ถ้า Endpoint ของเราไม่ได้มีการ Shared การใช้งาน Resource ในลักษณะของ Azure Table ก็ยังถือว่าปลอดภัยอยู่ครับ&lt;&#x2F;p&gt;
&lt;p&gt;แล้วพบกันใหม่นะครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>จัดการการวน Loop ของ Callback ใน JavaScript</title>
		<published>2024-12-27T00:00:00+00:00</published>
		<updated>2024-12-27T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/handle-loop-of-callback-in-javascript/" type="text/html"/>
		<id>https://thadaw.com/posts/handle-loop-of-callback-in-javascript/</id>
		<content type="html">&lt;p&gt;สวัสดีครับ วันนี้เรามาจัดการเรื่องที่น่าปวดหัวของ JavaScript กัน ซึ่งถ้าใครเขียน Promise อยู่บ่อยๆ อยู่แล้ว ก็คงไม่ค่อยเจอกับปัญหาพวกนี้เท่าไหร่แล้วเนอะ แต่ถ้าคนที่เขียน JavaScript ยุคสมัยของ Callback อยู่ ก็คงเจอปัญหานี้บ่อยๆ แล้ว ซึ่งจะต้องเข้าใจการทำงานของ JavaScript Event Loop ก่อน&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;handle-loop-of-callback-in-javascript&#x2F;.&#x2F;cover.jpg&quot; alt=&quot;cover&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;โดยเจ้า Callback เนี่ยแหละสร้างความปวดหัวในการทำงาน สำหรับคนที่คุ้นเคยกับเขียนแบบ Async&#x2F;Await มากๆ เลย เพราะมันไม่ได้ทำงานตามลำดับที่เราคิด แต่มันจะเอาไปทำงานหลังบ้าน แล้วก็เสร็จเมื่อไหร่ก็ไม่รู้เลย 555+ น้ำตาจิไหล&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;callout note&quot;&gt;
    
    &lt;div class=&quot;icon&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;path d=&quot;M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 7H13V9H11V7ZM11 11H13V17H11V11Z&quot; fill=&quot;currentColor&quot;&gt;&lt;&#x2F;path&gt;&lt;&#x2F;svg&gt;
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;content&quot;&gt;
        
        &lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
        
        &lt;p&gt;ถึงแม้บทความนี้จะเขียนพฤติกรรมของ JavaScript แต่จะใช้ภาษา TypeScript ในการเขียนตัวอย่าง ใครที่อยากจะลองรันตาม
แนะนำใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;bun.sh&#x2F;&quot;&gt;bun&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;p&lt;&#x2F;span&gt; demo-callback&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-and z-shell&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-cd z-shell&quot;&gt;cd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; demo-callback&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-and z-shell&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;bun&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; init&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นมันจะสร้างไฟล์ index.ts ให้เรา แล้วเราก็เริ่มเขียนโค้ดตามตัวอย่างได้เลย
โดยให้รันด้วยคำสั่ง &lt;code&gt;bun run index.ts&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;เรามาดูตัวอย่างของจริงกัน อย่างเช่น ปัญหา Classic อย่างเจ้า timeout กันก่อน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;setTimeout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Timeout 1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Start&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถ้าเรามองผ่านๆ เราอาจจะคิดว่ามันจะทำตามลำดับ ก็คือเริ่มด้วย &lt;code&gt;Timeout 1&lt;&#x2F;code&gt; แต่จริงๆ แล้วมันจะทำงานแบบนี้&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Start
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Timeout 1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;หมายความว่า มันจะทำงาน &lt;code&gt;Start&lt;&#x2F;code&gt; ก่อนแล้วค่อยทำ &lt;code&gt;Timeout 1&lt;&#x2F;code&gt; หลังจาก 1 วินาที ซึ่งถ้าเราไม่เข้าใจหลักการของ Event Loop นี้เราจะทำให้เราอ่านโค๊ดแล้วไม่เข้าใจ ถ้าเราต้องการทำงานตามลำดับ ให้ใช้ Promise หรือ Async&#x2F;Await ก็ได้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;timeout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-return z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;void&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;ms&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Promise&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;resolve&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;setTimeout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;fn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;resolve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;ms&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Start&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;timeout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Timeout 1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เราก็จัดการแปลงเจ้า &lt;code&gt;setTimeout&lt;&#x2F;code&gt; ให้เป็น Promise แล้วเรียกใช้งานด้วย &lt;code&gt;await&lt;&#x2F;code&gt; แล้วก็จะทำงานตามลำดับที่เราคิด&lt;&#x2F;p&gt;
&lt;h2 id=&quot;payhaakh-ngeraakh-ngkaarcchadkaar-loop-ain-callback&quot;&gt;ปัญหาของเราของการจัดการ Loop ใน Callback&lt;a class=&quot;zola-anchor&quot; href=&quot;#payhaakh-ngeraakh-ngkaarcchadkaar-loop-ain-callback&quot; aria-label=&quot;Anchor link for: payhaakh-ngeraakh-ngkaarcchadkaar-loop-ain-callback&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;อย่างเขียนไปตรงหัวข้อว่า เรื่องของจัดการการวน Loop ของ Callback ใน JavaScript นั้น
ซึ่งถ้าเป็น Modern JavaScript เรามักจะใช้ Promise เป็นมาตรฐานในการจัดการ Async แล้ว
แต่เราก็อาจจะต้องทำงานกับบาง Library หรือโค้ดที่เขียนแบบ Callback อยู่ ซึ่งเราก็จะต้องเข้าใจการทำงานของ JavaScript Event Loop ก่อน&lt;&#x2F;p&gt;
&lt;p&gt;ผมเองก็ได้มีโอกาสใช้ Library ตัวนึง สำหรับทำ Search แบบ Lightweight ชื่อ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nextapps-de&#x2F;flexsearch&quot;&gt;Flexsearch&lt;&#x2F;a&gt; มาลองดูตัวอย่างกัน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;FlexSearch&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;flexsearch&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;index&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;FlexSearch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Document&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Index configuration&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Somehow we add data into index&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Export the index&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;index&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;export&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;fs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;writeFileSync&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;join&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;searchIndexPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;.json&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-json z-ts&quot;&gt;JSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-json z-ts&quot;&gt;stringify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;data&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;??&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เราจะเห็นว่าเราจะใช้ &lt;code&gt;index.export&lt;&#x2F;code&gt; ในการ Export ข้อมูลออกมา แต่เราจะเจอปัญหาเรื่องการวน Loop ของ Callback ที่เราไม่รู้ว่าเมื่อไหร่จะเสร็จ แล้วเราจะทำอย่างไร แล้วมันเป็นปัญหายังไง มาดูตัวอย่างที่ทำให้เกิดปัญหากัน&lt;&#x2F;p&gt;
&lt;p&gt;สมมติว่าต้องการเก็บว่าเจ้า method ที่ชื่อ &lt;code&gt;export&lt;&#x2F;code&gt; มีค่าของ &lt;code&gt;key&lt;&#x2F;code&gt; อะไรบ้าง ซึ่งเราไม่มีทางรู้ได้เลยใช่มั้ยว่ามันค่าอะไรบ้าง ดังนั้นเราจึงต้อง
หาอะไรมาเก็บมัน เช่น&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;index&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;export&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;fs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;writeFileSync&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;join&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;searchIndexPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;.json&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-json z-ts&quot;&gt;JSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-json z-ts&quot;&gt;stringify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;data&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;??&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Exported keys:&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;คำถามคือ บรรทัดสุดท้ายที่แสดงค่าของ &lt;code&gt;keys&lt;&#x2F;code&gt; ออกมา จะแสดงค่าอะไรออกมา
คำตอบคือ มันจะแสดงค่าว่า &lt;code&gt;[]&lt;&#x2F;code&gt; ก็คือไม่มีค่่าอะไรเลย ซึ่งหมายความว่ามัน &lt;code&gt;export&lt;&#x2F;code&gt; เสร็จหลังจากที่เราแสดงค่าออกมาแล้ว&lt;&#x2F;p&gt;
&lt;p&gt;แล้วถ้าเราใส่ Async&#x2F;Await ลงไปใน callback function ดูล่ะ จะเป็นยังไง&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;index&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;export&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-async z-ts&quot;&gt;async&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;fs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;writeFile&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;join&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;searchIndexPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;.json&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-json z-ts&quot;&gt;JSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-json z-ts&quot;&gt;stringify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;data&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;??&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แบบนี้มีผลเหมือนเดิม ก็คือ ถึงแม้ว่าแต่ใน Callback จะเป็น Async แล้ว แต่ระหว่างการทำงานของ Callback นั้น มันจะไม่รอให้เสร็จก่อน แล้วค่อยทำต่อ แต่มันจะทำงานต่อไปเลย แล้วค่อยทำ Callback ต่อไป ซึ่งเราจะเห็นว่า &lt;code&gt;keys&lt;&#x2F;code&gt; จะยังเป็น &lt;code&gt;[]&lt;&#x2F;code&gt; อยู่เหมือนเดิม&lt;&#x2F;p&gt;
&lt;h2 id=&quot;withiikaaraekpayhaakaarwn-loop-kh-ng-callback&quot;&gt;วิธีการแก้ปัญหาการวน Loop ของ Callback&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiikaaraekpayhaakaarwn-loop-kh-ng-callback&quot; aria-label=&quot;Anchor link for: withiikaaraekpayhaakaarwn-loop-kh-ng-callback&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;วิธีนี้เราควรจะรู้จำนวนที่แน่นอนว่า Callback นั้นจะทำงานกี่ครั้ง ซึ่งในกรณีนี้ผมจะสังเกตุพฤติกรรมของ &lt;code&gt;index.export&lt;&#x2F;code&gt; ว่ามันจะเรียก Callback กี่ครั้ง แล้วเราจะใช้ Promise ในการจัดการ&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งแนวคิดก็คือ เราจะสร้าง function ขึ้นมา 3 function ซึ่งทำหน้าที่ควบคุมการทำงานของ Callback และคอยตรวจสอบ
ว่าเจ้า Callback จะทำเสร็จเมื่อไหร่&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;function แรก ก็คือเราจะกำหนดก่อนว่า callback นั้นจะทำงานกี่ครั้ง&lt;&#x2F;li&gt;
&lt;li&gt;function ที่สอง เราจะสร้างเป็น High-Order Function ที่จะรับ callback แล้วคอยเรียก callback นั้น และเมื่อ Callback นั้นทำงานเสร็จให้ลบ Counter ที่มาจาก Function แรกลง&lt;&#x2F;li&gt;
&lt;li&gt;เขียน Promise ที่จะรอให้ Counter ที่มาจาก Function แรก ถูกลบหมด แล้วค่อย resolve&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;จากขั้นตอนพวกนี้ เพื่อให้เห็นภาพมากขึ้น ผมจะเริ่มเขียนโค๊ดให้ดู&lt;&#x2F;p&gt;
&lt;h3 id=&quot;function-thii-1-sraang-object-kh-ng-callbackwaiter&quot;&gt;Function ที่ 1: สร้าง Object ของ CallbackWaiter&lt;a class=&quot;zola-anchor&quot; href=&quot;#function-thii-1-sraang-object-kh-ng-callbackwaiter&quot; aria-label=&quot;Anchor link for: function-thii-1-sraang-object-kh-ng-callbackwaiter&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;สำหรับกำหนดจำนวนครั้งที่ Callback จะทำงาน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;totalIndexFiles&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;15&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ตรงนี้เรารู้จำนวนที่แน่นอนว่ามันจะทำงานกี่ครั้ง&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;callbackWaiter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;CallbackWaiter&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;totalIndexFiles&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จะเห็นได้ว่าเราจะสร้าง Object ขึ้นมาเพื่อกำหนดว่า Callback จะทำงานกี่ครั้ง โดยกำหนดชื่อ Class ว่า &lt;code&gt;CallbackWaiter&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;function-thii-2-sraang-high-order-function-samhrab-callback&quot;&gt;Function ที่ 2: สร้าง High-Order Function สำหรับ Callback&lt;a class=&quot;zola-anchor&quot; href=&quot;#function-thii-2-sraang-high-order-function-samhrab-callback&quot; aria-label=&quot;Anchor link for: function-thii-2-sraang-high-order-function-samhrab-callback&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;จากตรงนี้เราจะเห็นว่า เจ้า &lt;code&gt;index.export&lt;&#x2F;code&gt; ไม่ได้จัดการให้เลยว่าเราจะรันยังไง รันไปกี่รอบแล้ว แล้วจะเสร็จเมื่อไหร่
แสดงว่าเราต้องหากลไกภายนอกมาควบคุมการทำงานของมันแทน โดยใช้ Class ที่เราสร้างขึ้นมา&lt;&#x2F;p&gt;
&lt;p&gt;โดย method ที่ว่า &lt;code&gt;execute&lt;&#x2F;code&gt; จะรับ callback แล้วคอยเรียก callback นั้น และเมื่อ Callback นั้นทำงานเสร็จให้ลบ Counter ที่มาจาก Function แรกลง เพื่อคอยตรวจสอบว่าเสร็จหรือยัง&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;index&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;export&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;callbackWaiter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;execute&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;fs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;writeFileSync&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;join&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;searchIndexPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;.json&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-json z-ts&quot;&gt;JSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-json z-ts&quot;&gt;stringify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;data&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;??&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;function-thii-3-sraang-promise-samhrabr-aih-callback-thamngaanesrcch&quot;&gt;Function ที่ 3: สร้าง Promise สำหรับรอให้ Callback ทำงานเสร็จ&lt;a class=&quot;zola-anchor&quot; href=&quot;#function-thii-3-sraang-promise-samhrabr-aih-callback-thamngaanesrcch&quot; aria-label=&quot;Anchor link for: function-thii-3-sraang-promise-samhrabr-aih-callback-thamngaanesrcch&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;จากตรงนี้เราจะเห็นว่าเราจะสร้าง Promise ขึ้นมาเพื่อรอให้ Counter ที่มาจาก Function แรก ถูกลบหมด
เมื่อทำงานเสร็จแล้วเราจึงปล่อยให้ทำงานอื่นต่อไป&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;callbackWaiter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;wait&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากตรงนี้เราจะเห็นว่าเราจะรอให้ Callback ทำงานเสร็จก่อน แล้วค่อยทำงานต่อไป&lt;&#x2F;p&gt;
&lt;h2 id=&quot;srupphaaphrwm&quot;&gt;สรุปภาพรวม&lt;a class=&quot;zola-anchor&quot; href=&quot;#srupphaaphrwm&quot; aria-label=&quot;Anchor link for: srupphaaphrwm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เพื่อให้เข้าใจง่ายขึ้น ผมจะเขียนโค๊ดทั้งหมดให้ดู&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;totalIndexFiles&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;15&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ตรงนี้เรารู้จำนวนที่แน่นอนว่ามันจะทำงานกี่ครั้ง&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;callbackWaiter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;CallbackWaiter&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;totalIndexFiles&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;index&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;export&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;callbackWaiter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;execute&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;fs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;writeFileSync&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;join&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;searchIndexPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;.json&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-json z-ts&quot;&gt;JSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-json z-ts&quot;&gt;stringify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;data&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;??&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;callbackWaiter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;wait&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากตรงนี้เราจะเห็นว่าเราจะรอให้ Callback ทำงานเสร็จก่อน แล้วค่อยทำงานต่อไป
และมั่นใจว่าเราจะทำงานตามลำดับที่เราคิด&lt;&#x2F;p&gt;
&lt;p&gt;และเพื่อให้เข้าใจมากขึ้น ผมจะเขียน Class ที่เราสร้างขึ้นมาให้ดู&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;CallbackWaiter&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;  &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;private&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;numberOfCallbackCalled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Function ที่ 1: สร้าง Object ของ CallbackWaiter&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-storage z-type z-ts&quot;&gt;constructor&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;totalCallback&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;numberOfCallbackCalled&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;totalCallback&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Function ที่ 2: สร้าง High-Order Function สำหรับ Callback &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; และเมื่อ Callback นั้นทำงานเสร็จให้ลบ Counter ที่มาจาก Function แรกลง&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;execute&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-return z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;fn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;numberOfCallbackCalled&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-decrement z-ts&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Function ที่ 3: สร้าง Promise สำหรับรอให้ Callback ทำงานเสร็จ&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ซึ่งจะคอยเข้าไปตรวจสอบค่าของ Counter ที่มาจาก Function แรก ว่าถึง 0 หรือยัง&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; โดยจะเข้าไปตรวจสอบทุกๆ 100 ms&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ถ้าเสร็จแล้ว ค่อย resolve เป็นอันเสร็จ&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-async z-ts&quot;&gt;async&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;wait&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;delay&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;100&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Promise&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;void&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Promise&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;resolve&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;interval&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;setInterval&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;numberOfCallbackCalled&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;          &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;clearInterval&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;interval&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;          &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;resolve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;delay&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ใครอยากดูโค๊ดทั้งหมด สามารถดูได้ที่ เพื่อให้เห็นภาพรวมตัวอย่างการใช้งานลองดูที่ Github ผมได้เลยนะ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;blog-v8&#x2F;blob&#x2F;fcac407eb275da4e448834b334e5c8c94f71db66&#x2F;snippets&#x2F;src&#x2F;libs&#x2F;search&#x2F;search-index-file.ts#L14-L36&quot;&gt;mildronize&#x2F;blog-v8&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thingthaay&quot;&gt;ทิ้งท้าย&lt;a class=&quot;zola-anchor&quot; href=&quot;#thingthaay&quot; aria-label=&quot;Anchor link for: thingthaay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เป็นยังไงกันบ้าง ถ้าเราเข้าใจหลักการของ JavaScript Event Loop ก็จะทำให้เราเข้าใจการหยุดรอการทำงานของ JavaScript
รวมถึงการเขียน Promise ครอบ Callback เพื่อให้เราทำงานตามลำดับที่เราคิด แต่ถ้าเราต้องทำงานกับ Callback ที่ไม่รู้ว่าจะทำงานกี่ครั้ง
จะทำได้มั้ยน้าาา 🤔 เอาเป็นว่าถ้าใครนึกออกว่าต้องเขียนยังไง ลองพิมพ์คอมมเมนต์มาดูนะครับ&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าใครชอบอย่าลืมกด Like หรือ Share ให้เพื่อนๆ ด้วยนะครับ แล้วเจอกันใหม่ในบทความต่อไปครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ทำความรู้จัก RKE2 (Rancher) ตัวช่วยจัดการ Kubernetes Cluster ที่ง่ายและสบายขึ้น</title>
		<published>2024-12-02T00:00:00+00:00</published>
		<updated>2024-12-02T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/get-to-know-rke2-rancher-an-easier-way-to-manage-kubernetes-cluster/" type="text/html"/>
		<id>https://thadaw.com/posts/get-to-know-rke2-rancher-an-easier-way-to-manage-kubernetes-cluster/</id>
		<content type="html">&lt;p&gt;เวลาที่เราพูดถึง &lt;strong&gt;Kubernetes&lt;&#x2F;strong&gt; มันจะมีสองมุมเสมอครับ ด้านหนึ่งคือฝั่ง &lt;strong&gt;Admin&lt;&#x2F;strong&gt; ที่ต้องคอย Setup และดูแล Cluster ตั้งแต่การติดตั้ง, การจัดการโหนด, ไปจนถึงการอัปเดตระบบ ส่วนอีกด้านคือฝั่ง &lt;strong&gt;Dev&lt;&#x2F;strong&gt; ที่ใช้ &lt;code&gt;kubectl&lt;&#x2F;code&gt; หรือเครื่องมือ CI&#x2F;CD เพื่อ deploy แอปพลิเคชันโดยไม่ต้องสนใจเบื้องหลังของคลัสเตอร์ สำหรับบทความนี้ ผมจะพาเรามาโฟกัสที่ฝั่ง Admin โดยเฉพาะ และแนะนำเครื่องมือที่ช่วยให้การสร้างและจัดการ Kubernetes Cluster ง่ายขึ้นอย่าง &lt;strong&gt;Rancher&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Rancher ถูกออกแบบมาเพื่อลดความยุ่งยากและซับซ้อนของการ Setup Cluster ทำให้ Admin สามารถสร้างและจัดการ Kubernetes ได้โดยไม่ต้องปวดหัวกับรายละเอียดที่ซับซ้อน ไม่ว่าคุณจะเป็นมือใหม่หรือผู้มีประสบการณ์ Rancher จะช่วยให้การทำงานของเราคล่องตัวขึ้น มารู้จัก Rancher ไปด้วยกัน แล้วคุณจะเห็นว่าการดูแล Kubernetes Cluster สามารถเป็นเรื่องง่ายได้จริงๆ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;get-to-know-rke2-rancher-an-easier-way-to-manage-kubernetes-cluster&#x2F;rancher.webp&quot; alt=&quot;rancher icon&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;kubernetes-ekhaamaaaekpayhaa-aair&quot;&gt;&lt;strong&gt;Kubernetes เข้ามาแก้ปัญหาอะไร&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#kubernetes-ekhaamaaaekpayhaa-aair&quot; aria-label=&quot;Anchor link for: kubernetes-ekhaamaaaekpayhaa-aair&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;Kubernetes หรือที่หลายคนเรียกสั้นๆ ว่า “K8s” เป็นแพลตฟอร์มจัดการ Container ที่ช่วยให้เราสามารถปรับใช้ (deploy), ขยายขนาด (scale), และจัดการแอปพลิเคชันที่รันอยู่ใน Container ได้อย่างอัตโนมัติและมีประสิทธิภาพ เหมือนเป็น “ผู้จัดการทีม” ที่คอยดูแลให้ทุกอย่างในระบบทำงานได้ราบรื่น Kubernetes เหมาะสำหรับคนที่ต้องการบริหารระบบขนาดใหญ่หรือแอปฯ แบบ microservices ที่ต้องการความยืดหยุ่นและเสถียรภาพครับ&lt;&#x2F;p&gt;
&lt;p&gt;ผมอยากพูดถึงปัญหาที่ Kubernetes ถูกออกแบบมาเพื่อแก้ไข และทำให้การจัดการแอปพลิเคชันและระบบ IT ของเราง่ายขึ้น มีประสิทธิภาพมากขึ้น และตอบสนองความต้องการในยุคปัจจุบัน&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;1. ความพร้อมใช้งานตลอดเวลา (Availability)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ในยุคนี้ ทุกคนคาดหวังว่าแอปฯ จะต้องพร้อมใช้งานตลอด 24 ชั่วโมง ไม่มีคำว่า “ดาวน์ไทม์” Kubernetes จัดการเรื่องนี้โดยการวางแผนการรันคอนเทนเนอร์ในหลายๆ โหนด และใช้แนวคิด “desired state” เทียบกับ “actual state” ถ้ามีการล่มหรือขัดข้อง ระบบจะมองว่ามันคือ “ความต่าง” ที่ต้องแก้ไข และจะจัดการปรับสถานะให้กลับมาเป็นเหมือนที่ต้องการ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;2. การพัฒนาและส่งมอบที่รวดเร็ว (CI&#x2F;CD)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;จากเดิม การพัฒนาแอปฯ มักเป็นแบบ monolithic ที่ใช้เวลาหลายเดือนในการปล่อยเวอร์ชันใหม่ๆ Kubernetes ช่วยทำให้กระบวนการ DevOps เป็นจริงได้ โดยใช้ไฟล์คอนฟิกและ desired state ในการตั้งค่าและรันงาน ซึ่งช่วยให้ทีมพัฒนาสามารถทดสอบและส่งมอบแอปฯ ได้อย่างต่อเนื่อง ทำให้ “พลาดเร็ว แก้เร็ว” ได้จริง&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;3. ความคุ้มค่าและประสิทธิภาพ (Efficiency)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ในอดีต การเตรียมระบบ IT มักมีค่าใช้จ่ายสูง เช่น ต้องมีเซิร์ฟเวอร์สำรองหลายตัวเพื่อรองรับการทำงาน Kubernetes ทำให้เราสร้างสภาพแวดล้อมใหม่ๆ ได้ง่าย เพียงแค่สร้าง namespace ทดสอบงาน และลบเมื่อเสร็จงาน ช่วยลดการใช้ทรัพยากรที่ไม่จำเป็น&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;4. การปรับขนาดอัตโนมัติ (Automate Scaling)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;การขยายระบบในอดีตมักใช้เวลานาน ตั้งแต่เพิ่มเซิร์ฟเวอร์ ติดตั้งแอปฯ และตั้งค่าต่างๆ Kubernetes ทำให้การเพิ่มหรือลดขนาดระบบง่ายขึ้น เช่น หากเราต้องการเพิ่ม pod จาก 2 เป็น 3 ก็แค่เปลี่ยนจำนวน replicas แล้วระบบจะจัดการเพิ่ม pod ให้เอง และด้วย Horizontal Pod Autoscaler (HPA) Kubernetes สามารถเพิ่มหรือลด pod ตามเมตริก เช่น CPU, memory หรือ response time ของแอปฯ ได้แบบอัตโนมัติ นอกจากนี้ยังมี Vertical Pod Autoscaler (VPA) และ Node Scaling ที่ช่วยปรับทรัพยากรของ pod และโหนดในคลัสเตอร์ให้เหมาะสมโดยอัตโนมัติ เช่น ช่วงกลางวันระบบอาจใช้ 10 โหนด แต่ตอนกลางคืนอาจเหลือแค่ 1 โหนด เพื่อประหยัดค่าใช้จ่าย&lt;&#x2F;p&gt;
&lt;p&gt;ทั้งหมดนี้ทำให้ Kubernetes ไม่เพียงช่วยให้เราจัดการระบบได้ง่ายขึ้น แต่ยังช่วยลดต้นทุนและเพิ่มความยืดหยุ่นให้กับระบบของเราอีกด้วยครับ&lt;&#x2F;p&gt;
&lt;h1 id=&quot;rancher-khuue-aair&quot;&gt;&lt;strong&gt;Rancher คืออะไร?&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#rancher-khuue-aair&quot; aria-label=&quot;Anchor link for: rancher-khuue-aair&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;ผมอยากเล่าให้ฟังว่า &lt;strong&gt;Rancher&lt;&#x2F;strong&gt; คืออะไร และมันเชื่อมโยงกับ &lt;strong&gt;Kubernetes&lt;&#x2F;strong&gt; ยังไง&lt;&#x2F;p&gt;
&lt;p&gt;Rancher คือแพลตฟอร์มบริหารจัดการ Kubernetes ที่ช่วยให้เราสามารถสร้างและจัดการคลัสเตอร์ Kubernetes ได้ทุกที่ ไม่ว่าจะเป็นคลาวด์ เช่น GKE (Google Kubernetes Engine), AKS (Azure Kubernetes Service), หรือ EKS (Amazon Elastic Kubernetes Service) หรือแม้แต่บนเซิร์ฟเวอร์ของเราเอง Rancher สามารถช่วยเราติดตั้ง Kubernetes ลงบนโหนด หรือแม้กระทั่งนำเข้าคลัสเตอร์ Kubernetes ที่มีอยู่แล้วเข้ามาจัดการในระบบ Rancher&lt;&#x2F;p&gt;
&lt;p&gt;จุดเด่นของ Rancher คือการเพิ่มคุณค่าบน Kubernetes ที่มีอยู่แล้ว ตัวอย่างเช่น:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;การรวมระบบยืนยันตัวตนและการควบคุมสิทธิ์ (RBAC)&lt;&#x2F;strong&gt;: Rancher ให้เราจัดการสิทธิ์การเข้าถึงคลัสเตอร์ทั้งหมดจากศูนย์กลาง เช่น ใช้ Active Directory สำหรับล็อกอิน หรือกำหนดนโยบายความปลอดภัยในทุกคลัสเตอร์ได้ในที่เดียว&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;การมอนิเตอร์และการแจ้งเตือน&lt;&#x2F;strong&gt;: Rancher ช่วยเราติดตามสุขภาพของคลัสเตอร์และทรัพยากรต่างๆ รวมถึงส่ง log ไปยังระบบภายนอกได้&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;การผสาน Helm และ DevOps Tools&lt;&#x2F;strong&gt;: Rancher มี Application Catalog ที่เชื่อมต่อกับ Helm และยังสามารถทำงานร่วมกับระบบ CI&#x2F;CD ภายนอก หรือใช้ Fleet ของ Rancher เองในการ deploy และอัปเดต workloads แบบอัตโนมัติ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Rancher เป็นเครื่องมือที่ช่วยให้ DevOps และ IT ทำงานได้ง่ายขึ้น ตัวอย่างเช่น:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;สำหรับ DevOps: Rancher มีอินเทอร์เฟซที่ใช้งานง่าย ไม่ต้องมีความรู้ลึกเกี่ยวกับ Kubernetes ก็สามารถบริหารจัดการ workloads ได้ และยังมีเครื่องมือเสริมอย่าง Rancher Catalog ที่รวม DevOps tools ไว้ให้พร้อมใช้งาน&lt;&#x2F;li&gt;
&lt;li&gt;สำหรับ IT: Rancher ช่วยให้แอดมินดูสถานะและกำลังการทำงานของคลัสเตอร์ทั้งหมดได้จากหน้าจอเดียว และตั้งค่าความปลอดภัยหรือ enforce นโยบายต่างๆ ได้ทั่วทั้งองค์กร&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;พูดง่ายๆ คือ Rancher เป็นตัวช่วยสำคัญที่ทำให้ Kubernetes พร้อมใช้งานในระดับโปรดักชัน และทำให้ทีม DevOps ของเราทำงานได้คล่องตัวขึ้น โดยที่ยังตอบโจทย์ข้อกำหนดของ IT ได้ครบถ้วนครับ&lt;&#x2F;p&gt;
&lt;h1 id=&quot;aenwkhidhlakkh-ng-rancher&quot;&gt;&lt;strong&gt;แนวคิดหลักของ Rancher&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#aenwkhidhlakkh-ng-rancher&quot; aria-label=&quot;Anchor link for: aenwkhidhlakkh-ng-rancher&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;ผมอยากจะเล่าให้ฟังเกี่ยวกับแนวคิดหลักของ Rancher ซึ่งเป็นซอฟต์แวร์ที่ช่วยบริหารจัดการ Kubernetes ได้แบบมีประสิทธิภาพและยืดหยุ่นมาก แนวคิดที่เป็นหัวใจสำคัญของ Rancher มีอยู่หลายอย่างที่น่าสนใจครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;epidkwaangdwy-open-source&quot;&gt;&lt;strong&gt;เปิดกว้างด้วย Open Source&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#epidkwaangdwy-open-source&quot; aria-label=&quot;Anchor link for: epidkwaangdwy-open-source&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Rancher ถูกสร้างขึ้นบนพื้นฐานของโอเพ่นซอร์ส ทุกส่วนของโค้ดและบริการที่เกี่ยวข้องล้วนเปิดให้เข้าถึงได้ฟรี ทำให้เกิดชุมชนขนาดใหญ่ที่มีทั้งผู้ใช้งานและผู้พัฒนาช่วยกันปรับปรุง แบ่งปันไอเดีย และสร้างเอกสารเพื่อช่วยเหลือกัน&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aimmiikaarphuukmad-no-lock-ins&quot;&gt;&lt;strong&gt;ไม่มีการผูกมัด (No Lock-ins)&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#aimmiikaarphuukmad-no-lock-ins&quot; aria-label=&quot;Anchor link for: aimmiikaarphuukmad-no-lock-ins&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Rancher ออกแบบมาเพื่อไม่ให้เราต้องติดอยู่กับเทคโนโลยีใดเทคโนโลยีหนึ่ง หรือแม้แต่ตัว Rancher เอง เช่น เราสามารถถอด Rancher ออกจากระบบได้โดยไม่กระทบกับคลัสเตอร์ที่ใช้งานอยู่ เพราะ Rancher เปิดทางให้เราจัดการคลัสเตอร์ได้โดยตรง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thuk-yaangkhuue-kubernetes-object&quot;&gt;&lt;strong&gt;ทุกอย่างคือ Kubernetes Object&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#thuk-yaangkhuue-kubernetes-object&quot; aria-label=&quot;Anchor link for: thuk-yaangkhuue-kubernetes-object&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ตั้งแต่ Rancher เวอร์ชัน 2.0 เป็นต้นมา Rancher เปลี่ยนมาเก็บข้อมูลทุกอย่างในรูปแบบ Kubernetes Object แทนฐานข้อมูล MySQL เดิม ซึ่งช่วยเพิ่มความสามารถในการขยายระบบ และทำให้เราสามารถเข้าถึงข้อมูลผ่าน API ของ Kubernetes ได้เลย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;stateless-aelayuuedhyun&quot;&gt;&lt;strong&gt;Stateless และยืดหยุ่น&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#stateless-aelayuuedhyun&quot; aria-label=&quot;Anchor link for: stateless-aelayuuedhyun&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เนื่องจาก Rancher ทุกส่วนเป็น Stateless หมายความว่า ถ้า Pod ของ Rancher ล่มหรือถูกทำลาย Kubernetes ก็สามารถสร้าง Pod ใหม่ขึ้นมาแทนได้โดยไม่กระทบกับการทำงาน&lt;&#x2F;p&gt;
&lt;h2 id=&quot;controller-model&quot;&gt;&lt;strong&gt;Controller Model&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#controller-model&quot; aria-label=&quot;Anchor link for: controller-model&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ทุกบริการของ Rancher ถูกออกแบบให้ทำงานบนแนวคิดของ Kubernetes Controller ซึ่งคอยตรวจสอบสถานะของระบบและปรับให้ตรงกับสถานะที่เราต้องการเสมอ นี่ช่วยให้ Rancher สามารถทำงานต่อเนื่องได้แม้จะเกิดความล้มเหลวในบางส่วน&lt;&#x2F;p&gt;
&lt;p&gt;แนวคิดเหล่านี้ทำให้ Rancher เป็นเครื่องมือที่ตอบโจทย์สำหรับการจัดการ Kubernetes ของเราได้อย่างคล่องตัวและมั่นใจครับ&lt;&#x2F;p&gt;
&lt;h1 id=&quot;rke-khuue-aair&quot;&gt;&lt;strong&gt;RKE คืออะไร&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#rke-khuue-aair&quot; aria-label=&quot;Anchor link for: rke-khuue-aair&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;การสร้าง Kubernetes Cluster แบบดั้งเดิมนั้นถือเป็นงานที่ซับซ้อนและใช้เวลามาก เรียกกันว่า &lt;strong&gt;“K8s the hard way”&lt;&#x2F;strong&gt; เพราะเราต้องทำหลายขั้นตอน เช่น การสร้างใบรับรอง (Certificates), การติดตั้งและตั้งค่า etcd, การเชื่อมต่อบริการต่างๆ อย่าง kube-apiserver, kube-controller-manager และ kube-scheduler รวมถึงการตั้งค่า worker nodes เพื่อเข้าร่วมคลัสเตอร์ กระบวนการนี้ซับซ้อนและเปลี่ยนแปลงได้ตามการพัฒนา Kubernetes จนผู้ใช้งานต้องเขียนสคริปต์หรือ Ansible Playbooks เพื่อช่วยจัดการ ซึ่งยังต้องอัปเดตอยู่เรื่อยๆ ตามการเปลี่ยนแปลงของ Kubernetes&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;RKE (Rancher Kubernetes Engine)&lt;&#x2F;strong&gt; เกิดขึ้นมาเพื่อลดความยุ่งยากเหล่านี้ Rancher ต้องการให้การสร้าง Kubernetes Cluster เป็นเรื่องง่ายทั้งสำหรับผู้ใช้งานทั่วไปและ Rancher Server เอง โดย RKE คือเครื่องมือสำหรับการจัดการและสร้างคลัสเตอร์ Kubernetes ที่ได้รับการรับรองจาก CNCF (Cloud Native Computing Foundation)&lt;&#x2F;p&gt;
&lt;h1 id=&quot;rke-thamngaan-yaangair&quot;&gt;&lt;strong&gt;RKE ทำงานอย่างไร?&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#rke-thamngaan-yaangair&quot; aria-label=&quot;Anchor link for: rke-thamngaan-yaangair&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;RKE ใช้หลักการสำคัญที่ทุกอย่างในคลัสเตอร์ Kubernetes จะถูกรันใน Docker Containers แทนการติดตั้งไบนารีลงบนระบบปฏิบัติการโดยตรง ซึ่งหมายความว่า RKE ไม่สนใจว่าระบบปฏิบัติการเป็นอะไร ตราบใดที่สามารถรัน Docker ได้&lt;&#x2F;p&gt;
&lt;p&gt;กระบวนการเริ่มต้นใช้งาน RKE คือการสร้างไฟล์ &lt;code&gt;cluster.yml&lt;&#x2F;code&gt; เพื่อกำหนดค่าคลัสเตอร์ เช่น จำนวนโหนดและการตั้งค่าของแต่ละส่วน จากนั้น RKE จะใช้ไฟล์นี้เพื่อรันคอนเทนเนอร์ที่จำเป็นสำหรับคลัสเตอร์ เช่น etcd, kube-apiserver, kube-controller-manager, และ kube-scheduler ทั้งหมดนี้ช่วยลดขั้นตอนที่ซับซ้อนและทำให้การสร้างคลัสเตอร์ง่ายขึ้น&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;RKE เหมาะกับใคร?&lt;&#x2F;strong&gt; RKE เหมาะสำหรับผู้ที่ต้องการสร้าง Kubernetes Cluster ได้อย่างรวดเร็วและยืดหยุ่น โดยไม่ต้องจัดการกับขั้นตอนที่ซับซ้อนของการติดตั้งและตั้งค่าแบบเดิม นอกจากนี้ RKE ยังรองรับการใช้งานบนหลายแพลตฟอร์มและเหมาะสำหรับการปรับแต่งการตั้งค่าต่างๆ อย่างเต็มที่ครับ&lt;&#x2F;p&gt;
&lt;h1 id=&quot;rke2-khuue-aair&quot;&gt;&lt;strong&gt;RKE2 คืออะไร?&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#rke2-khuue-aair&quot; aria-label=&quot;Anchor link for: rke2-khuue-aair&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;RKE2 หรือที่รู้จักในชื่อ &lt;strong&gt;RKE Government&lt;&#x2F;strong&gt; เป็นโซลูชัน Kubernetes รุ่นใหม่จาก Rancher ที่พัฒนาขึ้นเพื่อแก้ไขข้อจำกัดของ RKE เดิม และเพิ่มความง่ายในการตั้งค่าจากแนวคิดของ K3s โดย RKE2 ได้รับการรับรองจาก CNCF ว่าเป็น Kubernetes Distribution เต็มรูปแบบ และถูกออกแบบมาเพื่อตอบสนองความต้องการพิเศษขององค์กรรัฐบาลสหรัฐฯ โดยเฉพาะ เช่น การให้ระบบปลอดภัยสูงตั้งแต่เริ่มต้น&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aairthiithamaih-rke2-phiesskwaarunedim&quot;&gt;&lt;strong&gt;อะไรที่ทำให้ RKE2 พิเศษกว่ารุ่นเดิม?&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#aairthiithamaih-rke2-phiesskwaarunedim&quot; aria-label=&quot;Anchor link for: aairthiithamaih-rke2-phiesskwaarunedim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;1) ความปลอดภัยที่ออกแบบมาให้พร้อมใช้งาน (Secure by Default)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ใน RKE เราจำเป็นต้องตั้งค่าตาม &lt;em&gt;hardening guide&lt;&#x2F;em&gt; ด้วยขั้นตอนที่ยุ่งยากเพื่อให้ผ่านมาตรฐาน CIS แต่ RKE2 ออกแบบมาให้ปลอดภัยตั้งแต่เริ่มต้น โดยแทบไม่ต้องตั้งค่าเพิ่มเติม&lt;&#x2F;li&gt;
&lt;li&gt;รองรับ FIPS (Federal Information Processing Standards) ซึ่งเป็นข้อกำหนดที่สำคัญสำหรับลูกค้ารัฐบาลสหรัฐฯ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;2) รองรับระบบ ARM64 และการผสมผสานระหว่างสถาปัตยกรรม&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;RKE2 รองรับทั้ง ARM64 และ AMD64 เช่นเดียวกับ K3s ทำให้เราสามารถใช้ RKE2 บน Raspberry Pi หรือโหนดที่ใช้พลังงานต่ำได้&lt;&#x2F;li&gt;
&lt;li&gt;เราสามารถสร้างคลัสเตอร์ที่มีโหนดแบบผสม (ARM64 และ AMD64) และรัน workloads อย่าง multi-arch builds ได้อย่างง่ายดาย&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;3) การจัดการแบบ Self-Bootstrapping&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ใน RKE เดิม เราต้องนิยามคลัสเตอร์ด้วย YAML และใช้ไบนารี RKE เพื่อสร้างและจัดการ แต่ใน RKE2 โหนดใหม่สามารถเข้าร่วมคลัสเตอร์ได้ง่ายๆ โดยใช้ &lt;em&gt;registration endpoint&lt;&#x2F;em&gt; ที่โหนดหลัก โดยต้องการเพียง Load Balancer ภายนอกหรือ Round-robin DNS&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;4) รองรับ Helm ในตัว&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;RKE2 สร้างขึ้นเพื่อรองรับ Rancher Fleet ซึ่งช่วยให้บริการต่างๆ ในคลัสเตอร์ เช่น &lt;em&gt;cert-manager&lt;&#x2F;em&gt; และ &lt;em&gt;OPA Gatekeeper&lt;&#x2F;em&gt; ถูกติดตั้งอัตโนมัติผ่าน Helm&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;5) เปลี่ยนจาก Docker ไปใช้ containerd&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;RKE2 เลิกพึ่งพา Docker และเปลี่ยนไปใช้ containerd ทำให้ K8s components เช่น etcd และ kube-apiserver ถูกรันในรูปแบบ &lt;em&gt;static pods&lt;&#x2F;em&gt; ซึ่งจัดการโดย kubelet โดยตรง สิ่งนี้ช่วยให้การดูแลและแก้ไขปัญหาทำได้ง่ายขึ้น&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;6) โอเพ่นซอร์สเต็มรูปแบบ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;เช่นเดียวกับผลิตภัณฑ์อื่นๆ ของ Rancher, RKE2 เป็นโอเพ่นซอร์สแบบ 100% ไม่มีค่าใช้จ่ายหรือข้อจำกัดในการใช้งาน&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;thamaim-rke2-thuengehmaaakaberaa&quot;&gt;&lt;strong&gt;ทำไม RKE2 ถึงเหมาะกับเรา?&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaim-rke2-thuengehmaaakaberaa&quot; aria-label=&quot;Anchor link for: thamaim-rke2-thuengehmaaakaberaa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;RKE2 เป็นทางเลือกที่เหมาะสำหรับใครก็ตามที่ต้องการสร้างคลัสเตอร์ Kubernetes ที่มีความปลอดภัยสูง ใช้งานง่าย และสามารถปรับตัวกับความต้องการที่หลากหลายได้ดี ไม่ว่าจะเป็นองค์กรทั่วไปหรือรัฐบาล RKE2 ก็ช่วยให้เราบริหารจัดการ Kubernetes ได้สะดวกและมีประสิทธิภาพมากขึ้นครับ!&lt;&#x2F;p&gt;
&lt;h1 id=&quot;rancher-vs-rke-aetktaangkanyangaing&quot;&gt;&lt;strong&gt;Rancher vs. RKE: แตกต่างกันยังไง?&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#rancher-vs-rke-aetktaangkanyangaing&quot; aria-label=&quot;Anchor link for: rancher-vs-rke-aetktaangkanyangaing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;เวลาที่เราใช้ Rancher ในการจัดการ Kubernetes Cluster เรามักจะได้ยินคำว่า &lt;strong&gt;Rancher&lt;&#x2F;strong&gt;, &lt;strong&gt;RKE&lt;&#x2F;strong&gt;, และ &lt;strong&gt;Custom Cluster&lt;&#x2F;strong&gt; ซึ่งสำหรับมือใหม่อาจจะสับสนได้ง่ายว่าความแตกต่างและบทบาทของแต่ละส่วนคืออะไร ผมจะอธิบายให้เข้าใจง่ายๆ ว่าแต่ละตัวช่วยอะไรเราได้บ้าง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rancher-khuue-aair-1&quot;&gt;&lt;strong&gt;Rancher คืออะไร?&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#rancher-khuue-aair-1&quot; aria-label=&quot;Anchor link for: rancher-khuue-aair-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;อย่างที่เคยอธิบายไปข้างบนแล้วว่า Rancher คือเครื่องมือที่ช่วยให้เราสร้างและบริหาร Kubernetes Cluster ได้อย่างครบวงจร เหมือนเป็น “ผู้ช่วยจัดการ Kubernetes-as-a-Service” Rancher สามารถ:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;สร้าง, อัปเกรด, และบริหาร Cluster&lt;&#x2F;strong&gt; ได้ง่ายผ่าน Web UI หรือ API&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ทำงานร่วมกับ Kubernetes Providers ต่างๆ&lt;&#x2F;strong&gt; เช่น GKE, AKS, EKS หรือแม้กระทั่งนำเข้า Cluster ที่มีอยู่แล้ว&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;รองรับ Authentication และ Access Control&lt;&#x2F;strong&gt; ช่วยให้การบริหารสิทธิ์ผู้ใช้เป็นเรื่องง่าย&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;มีฟีเจอร์เสริมในตัว&lt;&#x2F;strong&gt; เช่น ระบบแจ้งเตือน, Logging, และ Pipeline สำหรับ CI&#x2F;CD&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Rancher ถูกออกแบบให้ติดตั้งง่ายในรูปแบบ Docker Container ซึ่งเราสามารถเริ่มต้นได้ด้วยคำสั่ง:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;docker run -d -p 80:80 -p 443:443 rancher&#x2F;rancher
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แต่สำหรับ Production ควรใช้ Rancher แบบ High Availability (HA) โดยติดตั้ง Rancher บน Kubernetes Cluster ที่สร้างด้วย RKE เพื่อให้มั่นใจในความเสถียรและป้องกันการล่ม&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rke-khuue-aair-1&quot;&gt;&lt;strong&gt;RKE คืออะไร?&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#rke-khuue-aair-1&quot; aria-label=&quot;Anchor link for: rke-khuue-aair-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เพื่อให้เข้าใจง่ายขึ้นก็คือ RKE (Rancher Kubernetes Engine) เป็นเครื่องมือ CLI ของ Rancher ที่ใช้สำหรับสร้างและบริหาร Kubernetes Cluster โดย RKE จะช่วยจัดการทุกอย่างตั้งแต่การติดตั้ง Kubernetes Components เช่น etcd, kube-apiserver, และ network add-ons ตามค่าที่เรากำหนดในไฟล์ &lt;code&gt;cluster.yml&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ข้อควรเข้าใจคือ &lt;strong&gt;RKE ไม่ได้ติดตั้ง Rancher ให้เรา&lt;&#x2F;strong&gt; แต่ RKE ใช้สร้าง Kubernetes Cluster ที่ Rancher สามารถนำไปบริหารต่อได้&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;สิ่งที่ต้องการสำหรับใช้งาน RKE:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;โหนดแต่ละตัวต้องมี SSH Key และ Docker ติดตั้งอยู่&lt;&#x2F;li&gt;
&lt;li&gt;สามารถเข้าถึง Docker Socket (&lt;code&gt;&#x2F;var&#x2F;run&#x2F;docker.sock&lt;&#x2F;code&gt;) ได้&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;หลังจากที่ RKE สร้าง Cluster เสร็จ มันจะสร้างไฟล์ kubeconfig ซึ่งเราสามารถใช้กับ &lt;code&gt;kubectl&lt;&#x2F;code&gt; เพื่อบริหาร Cluster ได้&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rancher-thamngaanrwmkab-rke-yangaing&quot;&gt;&lt;strong&gt;Rancher ทำงานร่วมกับ RKE ยังไง?&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#rancher-thamngaanrwmkab-rke-yangaing&quot; aria-label=&quot;Anchor link for: rancher-thamngaanrwmkab-rke-yangaing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Rancher ใช้ RKE ในการสร้าง Kubernetes Cluster อยู่เบื้องหลัง โดยมี 2 วิธีหลัก:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Rancher Launched Kubernetes: ใช้โหนดจาก Infrastructure Provider&lt;&#x2F;strong&gt;Rancher สามารถเชื่อมต่อกับผู้ให้บริการ เช่น AWS หรือ Azure เพื่อสร้างโหนดผ่าน Docker Machine Driver และกำหนดบทบาทของโหนดผ่าน Node Pools&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Custom Cluster: ใช้โหนดของเราเอง&lt;&#x2F;strong&gt;เราสามารถเพิ่มโหนดที่เรามีอยู่แล้วในระบบ โดยเพียงแค่ติดตั้ง Docker และรันคำสั่งที่ Rancher ให้มา โหนดเหล่านี้จะถูกเพิ่มเข้าไปใน Cluster พร้อมบทบาทที่กำหนด&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;srupkhwaamaetktaangrahwaang-rancher-kab-rke&quot;&gt;&lt;strong&gt;สรุปความแตกต่างระหว่าง Rancher กับ RKE&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#srupkhwaamaetktaangrahwaang-rancher-kab-rke&quot; aria-label=&quot;Anchor link for: srupkhwaamaetktaangrahwaang-rancher-kab-rke&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rancher&lt;&#x2F;strong&gt;: เป็นเครื่องมือบริหาร Kubernetes Cluster ผ่าน UI, API, และมีฟีเจอร์เสริมในตัว&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;RKE&lt;&#x2F;strong&gt;: เป็น CLI สำหรับสร้างและอัปเดต Kubernetes Cluster โดยตรง&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ทั้งสองทำงานร่วมกันได้อย่างลื่นไหล Rancher ใช้ RKE เพื่อสร้าง Cluster และเพิ่มฟีเจอร์การจัดการเพิ่มเติม เช่น การควบคุมสิทธิ์, การมอนิเตอร์, และ CI&#x2F;CD ทำให้การใช้งาน Kubernetes Cluster ง่ายและครบวงจรมากขึ้นครับ&lt;&#x2F;p&gt;
&lt;h1 id=&quot;bthsngthaay&quot;&gt;&lt;strong&gt;บทส่งท้าย&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#bthsngthaay&quot; aria-label=&quot;Anchor link for: bthsngthaay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;ทั้งหมดที่ผมเล่ามาคือภาพรวมของ &lt;strong&gt;RKE2 (Rancher)&lt;&#x2F;strong&gt; และความเกี่ยวข้องกับ Kubernetes ที่ช่วยให้เราจัดการคลัสเตอร์ได้ง่ายและสบายขึ้นมาก ไม่ว่าจะเป็นการเริ่มต้นจากศูนย์ด้วย RKE2, การใช้ Rancher เพื่อรวมศูนย์การจัดการ, หรือการเข้าใจความแตกต่างระหว่าง Rancher กับ RKE ทั้งหมดนี้ช่วยให้เราประหยัดเวลา ลดความซับซ้อน และเพิ่มประสิทธิภาพในการทำงาน&lt;&#x2F;p&gt;
&lt;p&gt;Rancher และ RKE2 ไม่ได้เป็นแค่เครื่องมือ แต่มันเป็น “ตัวช่วย” ที่ทำให้เราโฟกัสกับสิ่งสำคัญได้เต็มที่ ไม่ว่าจะเป็นการพัฒนาแอปพลิเคชัน หรือการจัดการระบบในระดับโปรดักชัน ผมหวังว่าบทความนี้จะช่วยให้เรามองเห็นว่า RKE2 และ Rancher สามารถเข้ามาเป็นส่วนหนึ่งในการทำงานของเราได้ยังไง&lt;&#x2F;p&gt;
&lt;p&gt;สุดท้ายนี้ หากใครกำลังมองหาวิธีทำให้ Kubernetes Cluster ของตัวเองเบาขึ้น ง่ายขึ้น และมีประสิทธิภาพมากขึ้น ผมแนะนำให้ลองใช้งาน RKE2 และ Rancher แล้วเราจะเข้าใจว่าทำไมมันถึงเป็นตัวเลือกที่ดีในยุคของ Kubernetes ครับ!&lt;&#x2F;p&gt;
&lt;p&gt;แล้วเจอกันใหม่ สวัสดีครับ&lt;&#x2F;p&gt;
&lt;h1 id=&quot;aang-ingaela-aanephimetim&quot;&gt;&lt;strong&gt;อ้างอิงและอ่านเพิ่มเติม&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#aang-ingaela-aanephimetim&quot; aria-label=&quot;Anchor link for: aang-ingaela-aanephimetim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;Rancher-Deep-Dive-enterprise-Kubernetes&#x2F;dp&#x2F;180324609X&quot;&gt;Rancher Deep Dive by Matthew Mattox&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Rancher: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;ranchermanager.docs.rancher.com&#x2F;&quot;&gt;https:&#x2F;&#x2F;ranchermanager.docs.rancher.com&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;RKE: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;rke.docs.rancher.com&#x2F;&quot;&gt;https:&#x2F;&#x2F;rke.docs.rancher.com&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;RKE2: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.rke2.io&#x2F;&quot;&gt;https:&#x2F;&#x2F;docs.rke2.io&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Rancher vs. RKE: What Is the Difference?: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.suse.com&#x2F;c&#x2F;rancher_blog&#x2F;rancher-vs-rke-what-is-the-difference&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.suse.com&#x2F;c&#x2F;rancher_blog&#x2F;rancher-vs-rke-what-is-the-difference&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>สร้างและจัดการ Virtual Machine บน Azure ด้วย TypeScript (Bun)</title>
		<published>2024-11-29T00:00:00+00:00</published>
		<updated>2024-11-29T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/create-and-manage-virtual-machine-on-azure-with-typescript-bun/" type="text/html"/>
		<id>https://thadaw.com/posts/create-and-manage-virtual-machine-on-azure-with-typescript-bun/</id>
		<content type="html">&lt;p&gt;สวัสดีครับ! วันนี้เราจะมาพูดถึงการสร้าง Virtual Machine (VM) บน Microsoft Azure โดยใช้ TypeScript ซึ่งเป็น Runtime ที่เร็วมากสำหรับ JavaScript และ TypeScript และในบทความนี้ เราจะอธิบายการเขียนสคริปต์ทีละส่วน พร้อมกับสอนการติดตั้งและการใช้งาน TypeScript แบบง่าย ๆ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;คุณสมบัติเด่นที่คุณจะได้จากการรันสคริปต์นี้&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;สร้าง Virtual Machine (VM) พร้อมกำหนดค่าต่าง ๆ เช่น ชื่อเครื่อง ขนาด และระบบปฏิบัติการ&lt;&#x2F;li&gt;
&lt;li&gt;เปิดพอร์ต 22 สำหรับ SSH อัตโนมัติ&lt;&#x2F;li&gt;
&lt;li&gt;ติดตั้ง Ansible บน VM พร้อมใช้งาน&lt;&#x2F;li&gt;
&lt;li&gt;กำหนด DNS ให้ VM เพื่อการเข้าถึงที่ง่ายขึ้น&lt;&#x2F;li&gt;
&lt;li&gt;ทุกขั้นตอนจัดการผ่าน CLI โดยใช้คำสั่ง Azure CLI ผ่าน Bun&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;kaartidtang-bun-aelakaaretriiymsphaaphaewdl-m&quot;&gt;&lt;strong&gt;การติดตั้ง Bun และการเตรียมสภาพแวดล้อม&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#kaartidtang-bun-aelakaaretriiymsphaaphaewdl-m&quot; aria-label=&quot;Anchor link for: kaartidtang-bun-aelakaaretriiymsphaaphaewdl-m&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;h1 id=&quot;1-tidtang-bun&quot;&gt;&lt;strong&gt;1. ติดตั้ง Bun&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-tidtang-bun&quot; aria-label=&quot;Anchor link for: 1-tidtang-bun&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;ก่อนอื่น คุณต้องติดตั้ง Bun ในระบบของคุณ:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;curl https:&#x2F;&#x2F;bun.sh&#x2F;install | bash
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;หลังจากติดตั้งเสร็จ ให้ตรวจสอบว่า Bun ทำงานได้ด้วยคำสั่ง&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;bun -v
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;2-sraangoprecchktaihmdwy-bun-init&quot;&gt;&lt;strong&gt;2. สร้างโปรเจกต์ใหม่ด้วย &lt;code&gt;bun init&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-sraangoprecchktaihmdwy-bun-init&quot; aria-label=&quot;Anchor link for: 2-sraangoprecchktaihmdwy-bun-init&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;bun init
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;คำสั่งนี้จะสร้างไฟล์ &lt;code&gt;package.json&lt;&#x2F;code&gt; พร้อมโครงสร้างโปรเจกต์พื้นฐานให้คุณ&lt;&#x2F;p&gt;
&lt;h1 id=&quot;script-aelakaarthamngaanainaetlaswn&quot;&gt;&lt;strong&gt;Script และการทำงานในแต่ละส่วน&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#script-aelakaarthamngaanainaetlaswn&quot; aria-label=&quot;Anchor link for: script-aelakaarthamngaanainaetlaswn&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;h1 id=&quot;script-thanghmd&quot;&gt;&lt;strong&gt;Script ทั้งหมด&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#script-thanghmd&quot; aria-label=&quot;Anchor link for: script-thanghmd&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;ด้านล่างเป็นโค้ดทั้งหมดที่เราจะอธิบายทีละส่วน:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; *&lt;span class=&quot;z-storage z-type z-class z-jsdoc&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tag z-jsdoc&quot;&gt;@&lt;&#x2F;span&gt;ref&lt;&#x2F;span&gt; https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;virtual-machines&#x2F;linux&#x2F;mac-create-ssh-keys
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;$&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;bun&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;fs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;fs&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Edit these variables&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;RESOURCE_GROUP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;rg-demo-vm-thada&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;LOCATION&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;southeastasia&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;VM_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;demovmthada&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;IMAGE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Ubuntu2204&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Get value from `az vm image list --output table`&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;SIZE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Standard_B1s&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; 1 Core&#x2F;Ram 1 GB, Get value from `az vm list-sizes --location ${LOCATION} --output table`&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;ADMIN_USER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;azureuser&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;SSH_PUBLIC_KEY_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-support z-variable z-object z-process z-ts&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-process z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-property z-ts&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;demovmthada&#x2F;id_rsa.pub&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;SSH_KEY_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-support z-variable z-object z-process z-ts&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-process z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-property z-ts&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;demovmthada&#x2F;id_rsa.pem&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createAzureVirtualMachine&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;RESOURCE_GROUP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;location&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;LOCATION&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;VM_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;IMAGE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;size&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;SIZE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;adminUser&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;ADMIN_USER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;sshPublicKeyPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;SSH_PUBLIC_KEY_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;sshKeyPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;SSH_KEY_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-async z-ts&quot;&gt;async&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createAzureVirtualMachine&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;location&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;image&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;size&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;adminUser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;sshPublicKeyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;sshKeyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;location&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;size&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;adminUser&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;sshPublicKeyPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;sshKeyPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Check if SSH key exists&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;fs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;existsSync&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;sshKeyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;SSH key not found at &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;sshKeyPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;. Please generate one using ssh-keygen.&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-variable z-object z-process z-ts&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-process z-ts&quot;&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;fs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;existsSync&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;sshPublicKeyPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;SSH public key not found at &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;sshPublicKeyPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;. Please generate one using ssh-keygen.&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-variable z-object z-process z-ts&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-process z-ts&quot;&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Creating resource group &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; in location &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;location&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;...&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tagged-template z-ts&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;az group create --name &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --location &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;location&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Creating VM &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; in resource group &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;...&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tagged-template z-ts&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;az vm create --resource-group &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --name &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --image &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --size &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;size&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --admin-username &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;adminUser&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --ssh-key-values &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;sshPublicKeyPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Opening port 22 for SSH on VM &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;...&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tagged-template z-ts&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;az vm open-port --port 22 --resource-group &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --name &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;vmIp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tagged-template z-ts&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;az vm list-ip-addresses --resource-group &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --name &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --query &amp;quot;[0].virtualMachine.network.publicIpAddresses[0].ipAddress&amp;quot; -o tsv&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;stdout&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;toString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;trim&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;VM public IP: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;vmIp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Assign DNS name&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;FQDN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;assignDnsName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;dnsLabel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;vmName&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tagged-template z-ts&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;ssh -o StrictHostKeyChecking=no -i &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;sshKeyPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;adminUser&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;@&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;FQDN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; sudo apt update&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tagged-template z-ts&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;ssh -o StrictHostKeyChecking=no -i &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;sshKeyPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;adminUser&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;@&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;FQDN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; sudo apt install -y ansible&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Ansible has been installed. You can SSH into the VM using: ssh -i &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;sshKeyPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;adminUser&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;@&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;FQDN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-async z-ts&quot;&gt;async&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;assignDnsName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;dnsLabel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;dnsLabel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Promise&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Retrieve the public IP resource associated with the VM&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Retrieving public IP resource for VM: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;...&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;publicIpName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tagged-template z-ts&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;az vm list-ip-addresses --resource-group &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --name &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --query &amp;quot;[0].virtualMachine.network.publicIpAddresses[0].name&amp;quot; -o tsv&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;stdout&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;toString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;trim&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;publicIpName&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Unable to find public IP resource for VM &amp;#39;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;vmName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&amp;#39;.&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-variable z-object z-process z-ts&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-process z-ts&quot;&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Check if the fqdn is already assigned&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;assignedFqdn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tagged-template z-ts&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;az network public-ip show --resource-group &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --name &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;publicIpName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --query &amp;quot;dnsSettings.fqdn&amp;quot; -o tsv&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;stdout&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;toString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;trim&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;assignedFqdn&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Public IP already has DNS name assigned: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;assignedFqdn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;assignedFqdn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Check if the DNS label is already in use&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Checking availability of DNS label: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dnsLabel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;...&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;dnsAvailability&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tagged-template z-ts&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;az network public-ip list --query &amp;quot;[?dnsSettings.domainNameLabel==&amp;#39;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dnsLabel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&amp;#39;]&amp;quot; -o tsv&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;stdout&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;toString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;trim&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dnsAvailability&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;DNS label &amp;#39;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dnsLabel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&amp;#39; is already in use. Please choose a different label.&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-variable z-object z-process z-ts&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-process z-ts&quot;&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Update the public IP with the DNS label&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Assigning DNS label &amp;#39;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dnsLabel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&amp;#39; to public IP: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;publicIpName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;...&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tagged-template z-ts&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;az network public-ip update --resource-group &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --name &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;publicIpName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --dns-name &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dnsLabel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Display the fully qualified domain name (FQDN)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;fqdn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tagged-template z-ts&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;az network public-ip show --resource-group &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;resourceGroup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --name &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;publicIpName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --query &amp;quot;dnsSettings.fqdn&amp;quot; -o tsv&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;stdout&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;toString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;trim&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;DNS name assigned! You can now access your VM at: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;fqdn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;fqdn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;kaarkamhndkhaaphuuenthaan&quot;&gt;&lt;strong&gt;การกำหนดค่าพื้นฐาน&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#kaarkamhndkhaaphuuenthaan&quot; aria-label=&quot;Anchor link for: kaarkamhndkhaaphuuenthaan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;RESOURCE_GROUP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;rg-demo-vm-thada&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;LOCATION&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;southeastasia&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;VM_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;demovmthada&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;IMAGE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Ubuntu2204&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;SIZE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Standard_B1s&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;ADMIN_USER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;azureuser&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;SSH_PUBLIC_KEY_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-support z-variable z-object z-process z-ts&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-process z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-property z-ts&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;demovmthada&#x2F;id_rsa.pub&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;SSH_KEY_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-support z-variable z-object z-process z-ts&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-process z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-property z-ts&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;demovmthada&#x2F;id_rsa.pem&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ในส่วนนี้ เราได้กำหนดค่าต่าง ๆ ที่จำเป็นสำหรับการสร้าง VM เช่น:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RESOURCE_GROUP&lt;&#x2F;code&gt;: ชื่อ Resource Group ใน Azure&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;LOCATION&lt;&#x2F;code&gt;: ตำแหน่งภูมิศาสตร์ของ VM&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;VM_NAME&lt;&#x2F;code&gt;: ชื่อของ VM&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;IMAGE&lt;&#x2F;code&gt;: ระบบปฏิบัติการของ VM&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;SIZE&lt;&#x2F;code&gt;: ขนาดของ VM&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ฟังก์ชันนี้ช่วยกำหนด DNS ให้กับ VM ทำให้สามารถเข้าถึงได้ด้วยชื่อที่จำง่ายขึ้น เช่น &lt;code&gt;demovmthada.southeastasia.cloudapp.azure.com&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;withiikaaraichngaan&quot;&gt;&lt;strong&gt;วิธีการใช้งาน&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiikaaraichngaan&quot; aria-label=&quot;Anchor link for: withiikaaraichngaan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;ol&gt;
&lt;li&gt;แก้ไขค่าต่าง ๆ เช่น &lt;code&gt;RESOURCE_GROUP&lt;&#x2F;code&gt;, &lt;code&gt;LOCATION&lt;&#x2F;code&gt; และ &lt;code&gt;VM_NAME&lt;&#x2F;code&gt; ตามที่ต้องการ&lt;&#x2F;li&gt;
&lt;li&gt;รันสคริปต์ด้วยคำสั่ง:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;bun run script.ts
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;หลังจากรันสำเร็จ คุณจะได้รับ IP และ DNS สำหรับการเชื่อมต่อ VM&lt;&#x2F;p&gt;
&lt;p&gt;เย้ ได้ Azure VM มาแล้ววว ใน 1 Command&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;create-and-manage-virtual-machine-on-azure-with-typescript-bun&#x2F;azure-vm.webp&quot; alt=&quot;เย้ ได้ Azure VM มาแล้ววว ใน 1 Command&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ไหนๆๆ ลองเช็คซิ DNS ของ VM มามั้ย มาเรียบร้อย&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;create-and-manage-virtual-machine-on-azure-with-typescript-bun&#x2F;azure-vm-dns-name.webp&quot; alt=&quot;ไหนๆๆ ลองเช็คซิ DNS ของ VM มามั้ย มาเรียบร้อย&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;DNS มาแว้วว&lt;&#x2F;p&gt;
&lt;p&gt;หลังจากนั้นก็ทดสอบ Login กับ DNS ได้เลย&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ssh -i ~&#x2F;.ssh&#x2F;demovmthada&#x2F;id_rsa.pem adminuser@demovmthada.southeastasia.cloudapp.azure.com
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;srup&quot;&gt;&lt;strong&gt;สรุป&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#srup&quot; aria-label=&quot;Anchor link for: srup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;บทความนี้แสดงให้เห็นถึงการสร้างและจัดการ Virtual Machine บน Azure อย่างมีประสิทธิภาพโดยใช้ TypeScript และ Azure CLI คุณสามารถปรับแต่งสคริปต์ตามความต้องการ เช่น เพิ่มการติดตั้งซอฟต์แวร์เพิ่มเติม หรือเปลี่ยนค่าต่าง ๆ เพื่อให้เหมาะกับโปรเจกต์ของคุณ!&lt;&#x2F;p&gt;
&lt;p&gt;ลองทำดู แล้วคุณจะพบว่า TypeScript (Bun) เป็นเครื่องมือที่เร็วและใช้ง่ายมากสำหรับงาน Automation! ที่สำคัญคือ Type Safe ด้วยนะเออ&lt;&#x2F;p&gt;
&lt;p&gt;อ้อ ลง Ansible ได้แว้วว จากนั้น ก็แท็กมือต่อจากใช้ Ansible ลุยต่อได้เยยย&lt;&#x2F;p&gt;
&lt;p&gt;จบ ล่ะ บุย&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ดึงไฟล์จาก Server มาที่เครื่องด้วยสิทธิ Root บน Ubuntu</title>
		<published>2024-11-28T00:00:00+00:00</published>
		<updated>2024-11-28T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/ubuntu-copy-files-remote-to-local-root-permissions/" type="text/html"/>
		<id>https://thadaw.com/posts/ubuntu-copy-files-remote-to-local-root-permissions/</id>
		<content type="html">&lt;p&gt;บางทีไฟล์ในเซิร์ฟเวอร์มันติดปัญหาเรื่อง &lt;strong&gt;สิทธิ์ (permissions)&lt;&#x2F;strong&gt; เพราะเป็นของผู้ใช้อื่น ทำให้เราใช้คำสั่ง &lt;strong&gt;&lt;code&gt;scp&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; ดึงไฟล์ออกมาไม่ได้ ถ้าเจอปัญหาแบบนี้ ลองทำตามวิธีนี้เลย ง่าย ๆ แค่ 2 ขั้นตอน!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;1-etriiymaiflainechirfew-r&quot;&gt;&lt;strong&gt;1. เตรียมไฟล์ในเซิร์ฟเวอร์&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-etriiymaiflainechirfew-r&quot; aria-label=&quot;Anchor link for: 1-etriiymaiflainechirfew-r&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ก่อนอื่น ไปที่เซิร์ฟเวอร์แล้วก็อปไฟล์ที่ต้องการไปไว้ในตำแหน่งที่ผู้ใช้ปัจจุบันเข้าถึงได้ และปรับสิทธิ์ให้เหมาะสม ตัวอย่างคำสั่ง:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ssh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;ttss-poc&#x2F;ttss-poc adminuser@ttss-dev.southeastasia.cloudapp.azure.com &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;sudo cp -r &#x2F;home&#x2F;ttssdev&#x2F;.ssh &#x2F;tmp&#x2F;ssh-ttssdev &amp;amp;&amp;amp; sudo chown -R adminuser:adminuser &#x2F;tmp&#x2F;ssh-ttssdev&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;คำอธิบายคำสั่งนี้แบบเข้าใจง่าย:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ssh&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: ใช้เชื่อมต่อไปที่เซิร์ฟเวอร์&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;i&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: ระบุไฟล์คีย์ส่วนตัว (private key) เพื่อยืนยันตัวตน&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;sudo cp -r&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: ก็อปไฟล์ที่ต้องการ (ในตัวอย่างคือ &lt;strong&gt;&lt;code&gt;.ssh&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;) ไปไว้ที่ตำแหน่งชั่วคราว &lt;strong&gt;&lt;code&gt;&#x2F;tmp&#x2F;ssh-ttssdev&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;sudo chown&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: เปลี่ยนเจ้าของไฟล์ให้เป็น &lt;strong&gt;&lt;code&gt;adminuser&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; เพื่อให้เราเข้าถึงได้&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;2-duengaiflklabmaathiiekhruue-ng&quot;&gt;&lt;strong&gt;2. ดึงไฟล์กลับมาที่เครื่อง&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-duengaiflklabmaathiiekhruue-ng&quot; aria-label=&quot;Anchor link for: 2-duengaiflklabmaathiiekhruue-ng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เมื่อไฟล์พร้อมแล้ว ใช้คำสั่ง &lt;strong&gt;&lt;code&gt;scp&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; ดึงกลับมาที่เครื่องเราได้เลย:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;scp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;ttss-poc&#x2F;ttss-poc&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;r&lt;&#x2F;span&gt; adminuser@ttss-dev.southeastasia.cloudapp.azure.com:&#x2F;tmp&#x2F;ssh-ttssdev &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;ssh-ttssdev&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;คำอธิบายคำสั่ง:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;scp&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: ใช้สำหรับโอนถ่ายไฟล์แบบปลอดภัย&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;r&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: ดึงโฟลเดอร์ทั้งโฟลเดอร์ (recursive)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;adminuser@...:&#x2F;tmp&#x2F;ssh-ttssdev&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: ระบุตำแหน่งไฟล์ในเซิร์ฟเวอร์&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;~&#x2F;ssh-ttssdev&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;: ระบุที่เก็บไฟล์ในเครื่องเรา&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;thamepn-bash-script-aichchamaidngaay&quot;&gt;&lt;strong&gt;ทำเป็น Bash Script ใช้ซ้ำได้ง่าย ๆ&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamepn-bash-script-aichchamaidngaay&quot; aria-label=&quot;Anchor link for: thamepn-bash-script-aichchamaidngaay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ถ้าไม่อยากมาพิมพ์คำสั่งยาว ๆ ทุกครั้ง ลองเขียนเป็น &lt;strong&gt;Bash Script&lt;&#x2F;strong&gt; แบบนี้:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; ตั้งค่าตัวแปร&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;REMOTE_USER&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;adminuser&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;REMOTE_HOST&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;ttss-dev.southeastasia.cloudapp.azure.com&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;REMOTE_PATH&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;home&#x2F;ttssdev&#x2F;.ssh&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;TMP_PATH&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;tmp&#x2F;ssh-ttssdev&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;LOCAL_PATH&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;ssh-ttssdev&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;SSH_KEY&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;ttss-poc&#x2F;ttss-poc&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; 1. ก็อปไฟล์ไปยังตำแหน่งที่เข้าถึงได้&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Preparing files on remote server...&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ssh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;SSH_KEY&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;REMOTE_USER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;@&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;REMOTE_HOST&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;sudo cp -r &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;REMOTE_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;TMP_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &amp;amp;&amp;amp; sudo chown -R &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;REMOTE_USER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;:&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;REMOTE_USER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;TMP_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; 2. ดึงไฟล์กลับมาที่เครื่อง&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Copying files to local machine...&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;scp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;SSH_KEY&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;r&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;REMOTE_USER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;@&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;REMOTE_HOST&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;:&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;TMP_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;LOCAL_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Files copied successfully to &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;LOCAL_PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;!&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;วิธีใช้งาน:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;สร้างไฟล์สคริปต์ เช่น &lt;strong&gt;&lt;code&gt;fetch_files.sh&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; แล้ววางโค้ดด้านบนลงไป&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ให้สิทธิ์รันไฟล์:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;chmod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; +x fetch_files.sh&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;รันสคริปต์ได้เลย:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;.&#x2F;fetch_files.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;srup&quot;&gt;สรุป&lt;a class=&quot;zola-anchor&quot; href=&quot;#srup&quot; aria-label=&quot;Anchor link for: srup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;การดึงไฟล์จากเซิร์ฟเวอร์ที่มีปัญหาเรื่องสิทธิ์เป็นงานที่ดูซับซ้อน แต่สามารถแก้ไขได้ง่าย ๆ ด้วยการเตรียมไฟล์ให้เข้าถึงได้บนเซิร์ฟเวอร์ และใช้คำสั่ง scp ดึงไฟล์กลับมาที่เครื่องของเรา ขั้นตอนนี้ปลอดภัยและไม่กระทบไฟล์ต้นฉบับโดยตรง นอกจากนี้ การเขียน Bash Script ยังช่วยให้กระบวนการนี้สะดวกและนำกลับมาใช้ซ้ำได้อย่างรวดเร็ว หากทำตามวิธีที่แนะนำในบทความนี้ คุณจะสามารถจัดการไฟล์ที่มีปัญหาเรื่องสิทธิ์ได้อย่างมืออาชีพและมีประสิทธิภาพ! 🚀ง&lt;&#x2F;p&gt;
&lt;p&gt;จบปิ้งง&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>[DevOps][Azure] วิธีการ Mount Disk ใน Ubuntu VM บน Azure</title>
		<published>2024-11-26T00:00:00+00:00</published>
		<updated>2024-11-26T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/mount-disk-on-azure-vm-ubuntu-easy-steps/" type="text/html"/>
		<id>https://thadaw.com/posts/mount-disk-on-azure-vm-ubuntu-easy-steps/</id>
		<content type="html">&lt;p&gt;สวัสดีครับเพื่อนๆ วันนี้จะมาแชร์วิธี Mount Disk บน VM ที่สร้างใน Azure กันครับ 🖥️ หลายคนอาจเคยเพิ่ม Disk เข้าไปใน VM แล้วงงว่า “ทำไม Disk ยังไม่มาโชว์ใน Path ที่ต้องการ?” ไม่ต้องห่วงครับ เดี๋ยวพาไล่ Step-by-Step แบบง่ายๆ ทำตามได้เลย!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;phllaphththiiaidcchaakkaar-aan-blog-nii&quot;&gt;&lt;strong&gt;ผลลัพธ์ที่ได้จากการอ่าน Blog นี้&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#phllaphththiiaidcchaakkaar-aan-blog-nii&quot; aria-label=&quot;Anchor link for: phllaphththiiaidcchaakkaar-aan-blog-nii&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;หลังจากอ่าน Blog นี้ คุณจะสามารถ:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ตรวจสอบ Disk ใหม่ใน VM ได้&lt;&#x2F;li&gt;
&lt;li&gt;สร้าง Partition และ Format Disk เพื่อใช้งาน&lt;&#x2F;li&gt;
&lt;li&gt;Mount Disk ไปยัง Path ที่ต้องการใน Linux&lt;&#x2F;li&gt;
&lt;li&gt;ตั้งค่าให้ Disk Mount อัตโนมัติทุกครั้งที่รีบูต VM&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;singthiikhwretriiymmaak-n-prerequisite&quot;&gt;&lt;strong&gt;สิ่งที่ควรเตรียมมาก่อน (Prerequisite)&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#singthiikhwretriiymmaak-n-prerequisite&quot; aria-label=&quot;Anchor link for: singthiikhwretriiymmaak-n-prerequisite&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ก่อนเริ่มทำตาม Blog นี้ ให้เตรียมสิ่งต่อไปนี้:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;VM ที่พร้อมใช้งานใน Azure&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;ต้องมีสิทธิ์เข้าถึง VM (ผ่าน SSH หรือ Console)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Disk ที่ถูกเพิ่มเข้า VM เรียบร้อย&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;สามารถเพิ่ม Disk ได้จาก Azure Portal หรือ CLI&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;พื้นฐานคำสั่ง Linux&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;เช่น การใช้ &lt;strong&gt;&lt;code&gt;lsblk&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;, &lt;strong&gt;&lt;code&gt;fdisk&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;, &lt;strong&gt;&lt;code&gt;sudo&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; และการแก้ไขไฟล์ด้วย &lt;strong&gt;&lt;code&gt;nano&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ถ้าพร้อมแล้ว ลุยกันเลยครับ! 🚀&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-echkh-disk-k-n&quot;&gt;&lt;strong&gt;1. เช็ค Disk ก่อน&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-echkh-disk-k-n&quot; aria-label=&quot;Anchor link for: 1-echkh-disk-k-n&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เริ่มจากเช็คว่า Disk ใหม่ของเราถูก detect แล้วหรือยัง และมี partitions หรือยัง ด้วยคำสั่งนี้:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;lsblk&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จาก output เราเห็นว่า Disk &lt;strong&gt;&lt;code&gt;sdc&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; ยังไม่มี partitions (TYPE ยังเป็น &lt;strong&gt;&lt;code&gt;disk&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; เปล่าๆ) ดังนั้นเราต้องมาจัดการ partition และ format ก่อนครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-sraang-partition&quot;&gt;&lt;strong&gt;2. สร้าง Partition&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-sraang-partition&quot; aria-label=&quot;Anchor link for: 2-sraang-partition&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ใช้คำสั่ง &lt;strong&gt;&lt;code&gt;fdisk&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; เพื่อสร้าง partition ใหม่:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; fdisk &#x2F;dev&#x2F;sdc&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ใน &lt;strong&gt;&lt;code&gt;fdisk&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;กด &lt;strong&gt;&lt;code&gt;n&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; เพื่อสร้าง partition ใหม่&lt;&#x2F;li&gt;
&lt;li&gt;กด Enter เพื่อเลือก default options&lt;&#x2F;li&gt;
&lt;li&gt;สุดท้าย กด &lt;strong&gt;&lt;code&gt;w&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; เพื่อบันทึกและออก&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;3-format-disk&quot;&gt;&lt;strong&gt;3. Format Disk&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-format-disk&quot; aria-label=&quot;Anchor link for: 3-format-disk&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เมื่อสร้าง partition เสร็จแล้ว (เช่น &lt;strong&gt;&lt;code&gt;&#x2F;dev&#x2F;sdc1&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;) ก็ต้อง format เป็นไฟล์ระบบ (filesystem) ก่อน mount:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkfs.ext4 &#x2F;dev&#x2F;sdc1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;4-sraang-mount-point&quot;&gt;&lt;strong&gt;4. สร้าง Mount Point&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-sraang-mount-point&quot; aria-label=&quot;Anchor link for: 4-sraang-mount-point&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;สร้าง directory ที่เราจะใช้ mount disk:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkdir&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;p&lt;&#x2F;span&gt; &#x2F;mnt&#x2F;data&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;5-mount-disk&quot;&gt;&lt;strong&gt;5. Mount Disk&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#5-mount-disk&quot; aria-label=&quot;Anchor link for: 5-mount-disk&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Mount partition เข้าที่ path &lt;strong&gt;&lt;code&gt;&#x2F;mnt&#x2F;data&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mount &#x2F;dev&#x2F;sdc1 &#x2F;mnt&#x2F;data&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;6-trwcchs-bwaa-mount-samercch&quot;&gt;&lt;strong&gt;6. ตรวจสอบว่า Mount สำเร็จ&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#6-trwcchs-bwaa-mount-samercch&quot; aria-label=&quot;Anchor link for: 6-trwcchs-bwaa-mount-samercch&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เช็คด้วยคำสั่งนี้:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;df&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;h&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถ้าเจอ &lt;strong&gt;&lt;code&gt;&#x2F;mnt&#x2F;data&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; พร้อมพื้นที่ disk โชว์อยู่ แปลว่าสำเร็จแล้วครับ 🎉&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;7-tangkhaaaih-mount-atonmatihlang-reboot&quot;&gt;&lt;strong&gt;7. ตั้งค่าให้ Mount อัตโนมัติหลัง Reboot&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#7-tangkhaaaih-mount-atonmatihlang-reboot&quot; aria-label=&quot;Anchor link for: 7-tangkhaaaih-mount-atonmatihlang-reboot&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ถ้าอยากให้ disk mount เองทุกครั้งหลังรีบูต ทำตามนี้:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;หาค่า UUID ของ disk:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; blkid&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;สมมติได้ output แบบนี้:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&#x2F;dev&#x2F;sdc1:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; UUID=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;abcd-1234&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; TYPE=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;ext4&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;แก้ไขไฟล์ &lt;strong&gt;&lt;code&gt;&#x2F;etc&#x2F;fstab&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; nano &#x2F;etc&#x2F;fstab&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แล้วเพิ่มบรรทัดนี้เข้าไป:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;UUID&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;abcd-1234&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&#x2F;mnt&#x2F;data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ext4 defaults 0 2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;บันทึกไฟล์แล้วลองทดสอบด้วย:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mount&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ถ้าไม่มี error ก็เรียบร้อยครับ! 🎊&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;phllaphththiikhaadhwang&quot;&gt;ผลลัพธ์ที่คาดหวัง&lt;a class=&quot;zola-anchor&quot; href=&quot;#phllaphththiikhaadhwang&quot; aria-label=&quot;Anchor link for: phllaphththiikhaadhwang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;mount-disk-on-azure-vm-ubuntu-easy-steps&#x2F;result.webp&quot; alt=&quot;Disk Mounted&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;srup&quot;&gt;&lt;strong&gt;สรุป&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#srup&quot; aria-label=&quot;Anchor link for: srup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เสร็จแล้วครับ! เพียงไม่กี่ขั้นตอน Disk ของเราก็พร้อมใช้งานใน Path &lt;strong&gt;&lt;code&gt;&#x2F;mnt&#x2F;data&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; ได้เลย ใครลองแล้วติดปัญหาตรงไหนมาคุยกันได้นะครับ 😊&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Run Container Docker on Mac M1 (Arm CPU) using Colima</title>
		<published>2024-10-09T00:00:00+00:00</published>
		<updated>2024-10-09T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/run-container-docker-on-mac-m1-arm/" type="text/html"/>
		<id>https://thadaw.com/posts/run-container-docker-on-mac-m1-arm/</id>
		<content type="html">&lt;p&gt;Docker provides a powerful tool for containerization, but running it on a Mac M1 with an ARM CPU requires a specific approach. This article introduces &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;abiosoft&#x2F;colima&quot;&gt;&lt;strong&gt;Colima&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;, a lightweight Docker runtime that serves as an alternative to Docker Desktop, providing a seamless experience for Apple Silicon users. Here, we will guide you through the process of setting up and using Colima on your Mac M1.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introduction-to-colima&quot;&gt;Introduction to Colima&lt;a class=&quot;zola-anchor&quot; href=&quot;#introduction-to-colima&quot; aria-label=&quot;Anchor link for: introduction-to-colima&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;abiosoft&#x2F;colima&quot;&gt;&lt;strong&gt;Colima&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt; is a fast and efficient Docker runtime designed for both Apple Silicon (M1) and Intel-based Macs. It simplifies the process of running Docker containers on Mac M1, ensuring compatibility with various architectures and offering an alternative to &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.docker.com&#x2F;products&#x2F;docker-desktop&#x2F;&quot;&gt;Docker Desktop&lt;&#x2F;a&gt;. Colima provides a reliable way to utilize Docker without the performance concerns often associated with running x86 containers on ARM-based systems.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;installation-and-setup-of-colima&quot;&gt;Installation and Setup of Colima&lt;a class=&quot;zola-anchor&quot; href=&quot;#installation-and-setup-of-colima&quot; aria-label=&quot;Anchor link for: installation-and-setup-of-colima&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;To begin using Colima, you first need to install it. This can be done via Homebrew with the following command:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;brew&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; install colima&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once installed, you can proceed with starting Colima.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;starting-colima&quot;&gt;Starting Colima&lt;a class=&quot;zola-anchor&quot; href=&quot;#starting-colima&quot; aria-label=&quot;Anchor link for: starting-colima&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;To run Docker commands with Colima, you must start the service. The command below initiates Colima, specifying the architecture to use:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;colima&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; start&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;arch&lt;&#x2F;span&gt; x86_64&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We recommend specifying the &lt;code&gt;x86_64&lt;&#x2F;code&gt; architecture, as some Docker images may not yet be available for ARM64. However, if you wish to run ARM64 containers, you can use the &lt;code&gt;--arch aarch64&lt;&#x2F;code&gt; option, or simply omit the flag to use the default architecture.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-docker-with-colima&quot;&gt;Using Docker with Colima&lt;a class=&quot;zola-anchor&quot; href=&quot;#using-docker-with-colima&quot; aria-label=&quot;Anchor link for: using-docker-with-colima&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;After starting Colima, you can execute Docker commands in the same manner as with Docker Desktop. For example, pulling and running an image can be done as follows:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; pull hello-world&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; run&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;rm&lt;&#x2F;span&gt; hello-world&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; rmi hello-world&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These commands will demonstrate the basic functionality of Docker within the Colima environment.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;stopping-colima&quot;&gt;Stopping Colima&lt;a class=&quot;zola-anchor&quot; href=&quot;#stopping-colima&quot; aria-label=&quot;Anchor link for: stopping-colima&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Since running Colima consumes system resources, it is advisable to stop it when not in use. To stop Colima, run the following command:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;colima&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; stop&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will release system resources and halt Docker operations.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;troubleshooting-colima&quot;&gt;Troubleshooting Colima&lt;a class=&quot;zola-anchor&quot; href=&quot;#troubleshooting-colima&quot; aria-label=&quot;Anchor link for: troubleshooting-colima&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;If you encounter issues while using Colima, the simplest solution is often to delete the Colima instance and restart it. This can be done with the following command:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;colima&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; delete&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The system will prompt you to confirm the deletion of the Colima instance and its settings. Typing &lt;code&gt;y&lt;&#x2F;code&gt; will proceed with the deletion.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-dive-with-colima&quot;&gt;Using Dive with Colima&lt;a class=&quot;zola-anchor&quot; href=&quot;#using-dive-with-colima&quot; aria-label=&quot;Anchor link for: using-dive-with-colima&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;If you are using &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;wagoodman&#x2F;dive&quot;&gt;Dive&lt;&#x2F;a&gt;, a tool for inspecting Docker images, you may encounter an issue with the Docker socket. To resolve this, you can create a symbolic link to the Docker socket by running:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ln&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;sf&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.colima&#x2F;docker.sock &#x2F;var&#x2F;run&#x2F;docker.sock&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that you will need to execute this command each time after starting Colima.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Colima provides an efficient and straightforward solution for running Docker containers on Mac M1 systems. By leveraging Colima, users can enjoy the benefits of Docker without encountering the compatibility issues that sometimes arise with Apple Silicon. Whether you are building applications or managing containerized environments, Colima offers a reliable alternative to Docker Desktop.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;common-issues-with-docker-on-mac-m1&quot;&gt;Common Issues with Docker on Mac M1&lt;a class=&quot;zola-anchor&quot; href=&quot;#common-issues-with-docker-on-mac-m1&quot; aria-label=&quot;Anchor link for: common-issues-with-docker-on-mac-m1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Occasionally, when building Docker images on the Mac M1, you may encounter platform-specific issues. For example, building with &lt;code&gt;esbuild&lt;&#x2F;code&gt; may result in errors due to the architecture mismatch. To resolve this, you can build images targeting the &lt;code&gt;amd64&lt;&#x2F;code&gt; platform:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; buildx build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;platform&lt;&#x2F;span&gt; linux&#x2F;amd64&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;t&lt;&#x2F;span&gt; image-name .&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;An example error during the build process might look like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;css&quot; class=&quot;language-css z-code&quot;&gt;&lt;code class=&quot;language-css&quot; data-lang=&quot;css&quot;&gt;&lt;span class=&quot;z-source z-css&quot;&gt;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;css
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-css&quot;&gt;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;Copy &lt;span class=&quot;z-entity z-name z-tag z-css&quot;&gt;code&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-css&quot;&gt;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;#0 2.159 &lt;span class=&quot;z-punctuation z-separator z-combinator z-css&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; esbuild src&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-css&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-class z-css&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-css&quot;&gt;.&lt;&#x2F;span&gt;ts&lt;&#x2F;span&gt; --bundle --platform=node --target=node16 --format=cjs --outfile=dist&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-css&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-class z-css&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-css&quot;&gt;.&lt;&#x2F;span&gt;cjs&lt;&#x2F;span&gt; --minify
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-css&quot;&gt;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;#0 2.159
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-css&quot;&gt;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;#0 2.255 &lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;app&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;node_modules&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-class z-css&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-css&quot;&gt;.&lt;&#x2F;span&gt;bin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;esbuild: 13: &lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;app&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;node_modules&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-class z-css&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-entity z-css&quot;&gt;.&lt;&#x2F;span&gt;bin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;..&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;esbuild&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;bin&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;esbuild: Exec format error
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-css&quot;&gt;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;#0 2.266  ELIFECYCLE  Command failed with exit &lt;span class=&quot;z-entity z-name z-tag z-css&quot;&gt;code&lt;&#x2F;span&gt; 126.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-css&quot;&gt;&lt;span class=&quot;z-meta z-selector z-css&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For further discussion on this topic, you can refer to the &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;evanw&#x2F;esbuild&#x2F;issues&#x2F;642&quot;&gt;esbuild issue&lt;&#x2F;a&gt; or consult resources like &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;nixieminton&#x2F;articles&#x2F;c0933bbaae43f1&quot;&gt;this article&lt;&#x2F;a&gt; for additional troubleshooting steps.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;a class=&quot;zola-anchor&quot; href=&quot;#references&quot; aria-label=&quot;Anchor link for: references&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.izumanetworks.com&#x2F;blog&#x2F;build-docker-on-apple-m&#x2F;&quot;&gt;How to Build Docker Images on Apple M-Series&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Mastering Table-Driven Unit Tests in TypeScript</title>
		<published>2024-02-17T00:00:00+00:00</published>
		<updated>2024-02-17T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/mastering-table-driven-unit-tests-in-type-script/" type="text/html"/>
		<id>https://thadaw.com/posts/mastering-table-driven-unit-tests-in-type-script/</id>
		<content type="html">&lt;p&gt;Hey there, fellow TypeScript enthusiasts!&lt;&#x2F;p&gt;
&lt;p&gt;Are you eager to enhance your TypeScript proficiency? Join me on an exploration of a potent technique for crafting unit tests: &lt;strong&gt;the table-driven approach&lt;&#x2F;strong&gt;. Whether you&#x27;re a seasoned developer or just beginning your TypeScript journey, this article promises to equip you with invaluable insights into writing efficient and maintainable unit tests. Let&#x27;s embark on this enlightening journey together!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;understanding-table-driven-unit-tests&quot;&gt;Understanding Table-Driven Unit Tests&lt;a class=&quot;zola-anchor&quot; href=&quot;#understanding-table-driven-unit-tests&quot; aria-label=&quot;Anchor link for: understanding-table-driven-unit-tests&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;In the realm of TypeScript testing, the concept of table-driven tests shines as a beacon of efficiency and clarity. But what exactly are table-driven tests, and why should you care?&lt;&#x2F;p&gt;
&lt;p&gt;Table-driven tests involve structuring test cases in a tabular format, empowering developers to manage and execute tests with remarkable efficiency. This approach proves invaluable, especially when dealing with functions that demand testing across various input-output permutations.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;unveiling-the-power-of-table-driven-tests&quot;&gt;Unveiling the Power of Table-Driven Tests&lt;a class=&quot;zola-anchor&quot; href=&quot;#unveiling-the-power-of-table-driven-tests&quot; aria-label=&quot;Anchor link for: unveiling-the-power-of-table-driven-tests&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s dive into a practical example utilizing Jest&#x2F;Vitest, a versatile testing framework widely adopted in the JavaScript and TypeScript communities:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;describe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Test getPostDirectory&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Case&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;prefixPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;contentPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;expected&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;cases&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Case&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;prefixPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;_post&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;contentPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;_post&#x2F;preview&#x2F;test&#x2F;my-post&#x2F;readme.md&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;expected&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;preview&#x2F;test&#x2F;my-post&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;prefixPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;_post&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;contentPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;_post&#x2F;preview&#x2F;test.md&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;expected&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;preview&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;prefixPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;_post&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;contentPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;_post&#x2F;preview.md&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;expected&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;prefixPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;_contents&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;contentPath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;_contents&#x2F;post&#x2F;preview.md&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;expected&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;post&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;test&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;each&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;cases&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;getPostDirectory(%s, %s) should be %s&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;prefixPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;contentPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;expected&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;expect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;getPostDirectory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;prefixPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;contentPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toEqual&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;expected&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;See &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mt-astro-template&#x2F;pull&#x2F;2&#x2F;files#diff-5d8bf088f3b546b8e580b6be694243cf704ff9b744db044c20123d730bc68638R34-R50&quot;&gt;full example&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In this snippet, we define a test suite &lt;code&gt;Test getPostDirectory&lt;&#x2F;code&gt; that encompasses multiple test cases encapsulated within a structured table. Each test case includes inputs (&lt;code&gt;prefixPath&lt;&#x2F;code&gt; and &lt;code&gt;contentPath&lt;&#x2F;code&gt;) and the expected output (&lt;code&gt;expected&lt;&#x2F;code&gt;). Leveraging &lt;code&gt;test.each&lt;&#x2F;code&gt;, we iterate over these cases, ensuring the function &lt;code&gt;getPostDirectory&lt;&#x2F;code&gt; behaves as expected under diverse scenarios.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Let&#x27;s break it down:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;describe&lt;&#x2F;code&gt;: Provides a descriptive container for grouping related tests.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;test.each&lt;&#x2F;code&gt;: Iterates over the defined test cases, dynamically generating individual tests for each case.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;cases&lt;&#x2F;code&gt;: Defined in a structured format, facilitating clarity and ease of maintenance.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;advantages-of-table-driven-testing&quot;&gt;Advantages of Table-Driven Testing&lt;a class=&quot;zola-anchor&quot; href=&quot;#advantages-of-table-driven-testing&quot; aria-label=&quot;Anchor link for: advantages-of-table-driven-testing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Embracing table-driven tests in your TypeScript projects offers a myriad of benefits:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Improved Organization&lt;&#x2F;strong&gt;: Structured test cases enhance clarity and maintainability.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Efficient Execution&lt;&#x2F;strong&gt;: Automate test case generation and execution, saving time and effort.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Scalability&lt;&#x2F;strong&gt;: Easily accommodate new test cases without cluttering the test suite.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;In conclusion, table-driven unit tests serve as a cornerstone of robust TypeScript testing practices. By adopting this approach, you pave the way for cleaner, more maintainable codebases and expedite the development process. So why wait? Dive in, harness the power of table-driven testing, and elevate your TypeScript projects to new heights of excellence!&lt;&#x2F;p&gt;
&lt;p&gt;Happy testing&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Reusable utility function for guarding type for complex object shape using Zod</title>
		<published>2024-02-13T00:00:00+00:00</published>
		<updated>2024-02-13T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/reusable-utility-function-for-guarding-type-for-complex-object-shape-using-zod/" type="text/html"/>
		<id>https://thadaw.com/posts/reusable-utility-function-for-guarding-type-for-complex-object-shape-using-zod/</id>
		<content type="html">&lt;p&gt;Hey there, fellow programmers!&lt;&#x2F;p&gt;
&lt;p&gt;Are you looking to level up your TypeScript skills? Dive into this blog where we explore a powerful technique for type guarding complex object shapes using &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;zod.dev&#x2F;&quot;&gt;Zod&lt;&#x2F;a&gt;. Whether you&#x27;re a seasoned developer or just getting started with TypeScript, this article will provide valuable insights into narrowing types and leveraging utility functions for efficient code validation. Let&#x27;s embark on this journey together!&lt;&#x2F;p&gt;
&lt;p&gt;Before delving into the details, let&#x27;s understand the concept of narrowing types in TypeScript. Narrowing type refers to the process of refining the possible types of a value, enabling us to handle objects correctly.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;narrowing-unknown-types&quot;&gt;Narrowing Unknown Types&lt;a class=&quot;zola-anchor&quot; href=&quot;#narrowing-unknown-types&quot; aria-label=&quot;Anchor link for: narrowing-unknown-types&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;In TypeScript, we often encounter scenarios where we need to validate unknown values against complex object shapes. This process, known as narrowing types, ensures that we handle object types accurately. Let&#x27;s consider an example to understand this concept better, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;mariusschulz.com&#x2F;blog&#x2F;the-unknown-type-in-typescript&quot;&gt;code from mariusschulz.com&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * A custom type guard function that determines whether
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * `value` is an array that only contains numbers.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;isNumberArray&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;value&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-expression z-is z-ts&quot;&gt;is&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-builtin z-ts&quot;&gt;Array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;isArray&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;every&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;element&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-typeof z-ts&quot;&gt;typeof&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;element&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-ts&quot;&gt;===&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;number&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;unknownValue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;23&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;42&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;isNumberArray&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;unknownValue&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Within this branch, `unknownValue` has type `number[]`,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; so we can spread the numbers as arguments to `Math.max`&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;max&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-math z-ts&quot;&gt;Math&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-math z-ts&quot;&gt;max&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-spread z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;unknownValue&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;max&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;play?#code&#x2F;GYVwdgxgLglg9mABDAzgORAWwEYFMBOAgvvgIYCeAFAG6kA2IuAXIuANZhwDuYAlC7Qa5kKRGCx58AbQC6iAN4AoRIny4oIfEkrKViYmXIA6VAYo16jXogBkNxIMZHc1AlVx1cmXGCiIAvAB8iFDkAA64cMCIHl4+fv6JiABE4jgEyby6vADcigC+iooQCCh+7Jw8AGqWzKxgHNxI-ohSAIwArAA0iABMAMw9ABw9ACxjvT1tAGwyeYow0ZSoGOlEJOYVTTVCvNZKKgD0h4gA6jBQABYwSFeoiNhkkJc9AAZb1bWviJekoqERRCvNKSWSvLq6Y6IFBwRBcYQQUhIFBhNSkAAmIUuwhBBFEf0QpHwAHMsPF-rDXgBZUhXIyYUgAD1euhKYDKiAZjICiBpdK5lCMQo+YB2VjyKjZMM8RjocGJlC5uQKQA&quot;&gt;Playground&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Validating complex object shapes can be challenging with traditional type guards. Therefore, let&#x27;s explore using Zod for type guarding complex objects.&lt;&#x2F;p&gt;
&lt;p&gt;Now, let&#x27;s narrow down and validate a Record Type using the Zod data validation library.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;z&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;zod&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;isRecord&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;object&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;object&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-expression z-is z-ts&quot;&gt;is&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;recordSchema&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;record&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;recordSchema&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;safeParse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;object&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;success&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;findLength&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;object&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;isRecord&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;object&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-builtin z-ts&quot;&gt;Object&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;object&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-ts&quot;&gt;length&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-trycatch z-ts&quot;&gt;throw&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Error&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Input object doesn&amp;#39;t support type&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;play?#code&#x2F;JYWwDg9gTgLgBAbzgLzgXzgMyhEcDkyEAJvgNwBQFmArgHYDGMwEdcwAzgEoCmD0xABQQARgCs+MAFxx6AazoQA7nQCUM0RKbsOcXvyjEAPBxhRgdAOYAaWXQXK6APkQU4cfnVNwofAQGUGAAseEABDOABeFAA6XwMhZBj5RRVBVVVKd18YGig2eIDg0LCYjjDMHgAFMKgOHmFxSVUymgYGHg4OSjQqWkZmViwLYgAZHisYIMataTsHFXU4OhoQER4oV3dgTDhBTn0BGebVLfcfHlz8uAB5JqYYuR4ATw5jphaAGwnLKaz0NxwKY4JTLHiggCiUBwUEEAAMAJJ0MA0eCaSRwYgQTp0fDwDg0MCQWBA55gHhwzIUNBAA&quot;&gt;Playground&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;However, writing custom functions everywhere for such validations can lead to code duplication. Thus, we can create a utility function to streamline the process.&lt;&#x2F;p&gt;
&lt;p&gt;While exploring utility functions, I came across a reusable utility function for guarding types for complex object shapes using Zod, shared by &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;ecyrbedev&#x2F;status&#x2F;1757318655799414830&quot;&gt;ecyrbedev&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For instance, let&#x27;s say we want to guard the type of a value that is an array of non-empty File Object using Zod:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;z&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;zod&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;is&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ZodType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;schema&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;value&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-expression z-is z-ts&quot;&gt;is&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;schema&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;safeParse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;success&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;is&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;test&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;array&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;instanceof&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class z-dom z-ts&quot;&gt;File&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;nonempty&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;test&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;^? const test: [File, ...File[]]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;play?#code&#x2F;JYWwDg9gTgLgBAbzgLzgXzgMyhEcDkyEAJvgNwBQFAxhAHYDO8wDcAvHADwAqcApgA8YfOsVbIAdAC0S3AJ5g+APgAUANwCGAGwCufAFxwddANZ0IAdzoAaOA2oALPiA2HuASkObdfOCxQSEDowYME8SuwRCBRwsXBQfDA6UHR2js4aEgwamHwAChpQDHzq2nruWTrU1HwMDJRoVLSM8MJM+sZmlqkcANoAupTAmCosKm0w1pKFUBpyKpLALRp0NRAjAGLAWnzuFeZ0zmAw83vuiDFxE5exAPS3AHoA-BSNQA&quot;&gt;Playground&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;In this blog post, we&#x27;ve explored the concept of narrowing types in TypeScript and how it enables us to validate unknown values against complex object shapes. We&#x27;ve also seen how Zod, a powerful data validation library, can streamline the process of type guarding. By leveraging reusable utility functions, we can write cleaner and more efficient code, reducing the risk of errors and enhancing code maintainability.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;a class=&quot;zola-anchor&quot; href=&quot;#wrapping-up&quot; aria-label=&quot;Anchor link for: wrapping-up&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;We hope you found this blog post insightful and informative! Keep exploring, experimenting, and leveling up your TypeScript skills. If you have any questions or feedback, feel free to reach out. Happy coding!&lt;&#x2F;p&gt;
&lt;p&gt;Until next time,
Thada&lt;&#x2F;p&gt;
&lt;h2 id=&quot;reference&quot;&gt;Reference&lt;a class=&quot;zola-anchor&quot; href=&quot;#reference&quot; aria-label=&quot;Anchor link for: reference&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Basic Typenarrowing (Thai) from: https:&#x2F;&#x2F;typescript-th.thadaw.com&#x2F;docs&#x2F;basic&#x2F;narrowing-type&lt;&#x2F;li&gt;
&lt;li&gt;Solution Code from &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;ecyrbedev&#x2F;status&#x2F;1757318655799414830&quot;&gt;ecyrbedev&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;q-a&quot;&gt;Q&amp;amp;A&lt;a class=&quot;zola-anchor&quot; href=&quot;#q-a&quot; aria-label=&quot;Anchor link for: q-a&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;ve received some insightful questions from our readers, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.facebook.com&#x2F;photo?fbid=885491666913829&amp;amp;set=a.486562490140084&quot;&gt;Thiti Baipad and Surapus Moonjaras&lt;&#x2F;a&gt;. Thank you both for your valuable inquiries! Let&#x27;s address them one by one.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;question-1-why-not-directly-use-zod-parse-instead-of-just-using-type-guards&quot;&gt;Question 1: Why not directly use zod.parse instead of just using type guards?&lt;a class=&quot;zola-anchor&quot; href=&quot;#question-1-why-not-directly-use-zod-parse-instead-of-just-using-type-guards&quot; aria-label=&quot;Anchor link for: question-1-why-not-directly-use-zod-parse-instead-of-just-using-type-guards&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;In a quick response, when writing the blog, I didn&#x27;t really dwell on this aspect much. I must admit, I was slightly distracted during the meeting.&lt;&#x2F;p&gt;
&lt;p&gt;A fresh perspective on this is that separating the function out adds to readability. As for dependencies, it still depends on what you both prefer.&lt;&#x2F;p&gt;
&lt;p&gt;If we were to write something like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;array&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;safeParse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;success&lt;&#x2F;span&gt;) &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; do something &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It might be a bit hard to read and doesn&#x27;t carry the same meaning as a sentence. We&#x27;d have to interpret it.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;question-2-what-s-the-reason-behind-applying-zod-schema-type-in-the-utility-function&quot;&gt;Question 2: What&#x27;s the reason behind applying Zod Schema type in the utility function?&lt;a class=&quot;zola-anchor&quot; href=&quot;#question-2-what-s-the-reason-behind-applying-zod-schema-type-in-the-utility-function&quot; aria-label=&quot;Anchor link for: question-2-what-s-the-reason-behind-applying-zod-schema-type-in-the-utility-function&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;The reason for this lies in the example function provided, which specifies the internal type of the Zod object. Admittedly, I&#x27;m not extensively knowledgeable about this, but understanding such aspects allows for flexibility and application in various scenarios.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;question-3-why-remove-zod-dependency-from-the-is-function&quot;&gt;Question 3: Why remove Zod dependency from the is function?&lt;a class=&quot;zola-anchor&quot; href=&quot;#question-3-why-remove-zod-dependency-from-the-is-function&quot; aria-label=&quot;Anchor link for: question-3-why-remove-zod-dependency-from-the-is-function&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;I&#x27;ve previously written an article on a generic TypeScript Validation Tool without relying solely on Zod, which &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.thadaw.com&#x2F;s&#x2F;z8daujr&#x2F;&quot;&gt;you can find here&lt;&#x2F;a&gt; (The article in Thai). Hence, it&#x27;s possible to extend this concept to remove the Zod dependency from the is function.&lt;&#x2F;p&gt;
&lt;p&gt;However, it doesn&#x27;t mean that every solution must adhere to my recommendations. It&#x27;s crucial to understand that we have various options and can apply them flexibly in different situations.&lt;&#x2F;p&gt;
&lt;p&gt;Thank you once again for your questions!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Publishing Docker Image on GitHub Package Publicly with Github Actions</title>
		<published>2024-02-03T00:00:00+00:00</published>
		<updated>2024-02-03T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/publish-docker-image-public-on-github-package-with-github-actions/" type="text/html"/>
		<id>https://thadaw.com/posts/publish-docker-image-public-on-github-package-with-github-actions/</id>
		<content type="html">&lt;p&gt;Greetings, readers! If you&#x27;ve been using Docker Hub for managing your Docker images, did you know that GitHub offers an alternative with GitHub Package? In this blog post, we&#x27;ll walk through the process of publishing your Docker images on GitHub Package, leveraging the power of GitHub Actions. This is particularly beneficial if you&#x27;re already hosting your code on GitHub. Let&#x27;s dive into the details and explore how to seamlessly integrate Docker image publishing into your GitHub workflows.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;setting-up-github-actions-workflow&quot;&gt;Setting Up GitHub Actions Workflow&lt;a class=&quot;zola-anchor&quot; href=&quot;#setting-up-github-actions-workflow&quot; aria-label=&quot;Anchor link for: setting-up-github-actions-workflow&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;To get started, create a GitHub Actions workflow file and configure it to build and publish your Docker image whenever changes are pushed to the main branch. We&#x27;ll be using GitHub Container Registry (ghcr.io) for our image hosting. Below is the workflow file that you can use as a template, adopted from the &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;actions&#x2F;publishing-packages&#x2F;publishing-docker-images#publishing-images-to-github-packages&quot;&gt;GitHub Official Documentation&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yml&quot; class=&quot;language-yml z-code&quot;&gt;&lt;code class=&quot;language-yml&quot; data-lang=&quot;yml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Create and publish a Docker image&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Configures this workflow to run every time a change is pushed to the branch called `release`.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-constant z-language z-boolean z-yaml&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;branches&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;REGISTRY&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;ghcr.io&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;IMAGE_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ github.repository }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; There is a single job in this workflow. It&amp;#39;s configured to run on the latest available version of Ubuntu.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;build-and-push-image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;runs-on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;ubuntu-latest&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;permissions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;contents&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;read&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;packages&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;write&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;steps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Checkout repository&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;actions&#x2F;checkout@v4&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Uses the `docker&#x2F;login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Log in to the Container registry&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;docker&#x2F;login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;registry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ env.REGISTRY }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;username&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ github.actor }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;password&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; This step uses [docker&#x2F;metadata-action](https:&#x2F;&#x2F;github.com&#x2F;docker&#x2F;metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` &amp;quot;meta&amp;quot; allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Extract metadata (tags, labels) for Docker&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;meta&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;docker&#x2F;metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;images&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ env.REGISTRY }}&#x2F;${{ env.IMAGE_NAME }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; This step uses the `docker&#x2F;build-push-action` action to build the image, based on your repository&amp;#39;s `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; It uses the `context` parameter to define the build&amp;#39;s context as the set of files located in the specified path. For more information, see &amp;quot;[Usage](https:&#x2F;&#x2F;github.com&#x2F;docker&#x2F;build-push-action#usage)&amp;quot; in the README of the `docker&#x2F;build-push-action` repository.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; It uses the `tags` and `labels` parameters to tag and label the image with the output from the &amp;quot;meta&amp;quot; step.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Build and push Docker image&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;docker&#x2F;build-push-action@v5&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-decimal z-yaml&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-yaml&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;tags&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ steps.meta.outputs.tags }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;labels&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ steps.meta.outputs.labels }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;cache-from&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;type=gha&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This workflow file is designed to run on every push to the &lt;code&gt;main&lt;&#x2F;code&gt; branch, ensuring that your Docker image is automatically built and published when changes occur.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;executing-the-workflow&quot;&gt;Executing the Workflow&lt;a class=&quot;zola-anchor&quot; href=&quot;#executing-the-workflow&quot; aria-label=&quot;Anchor link for: executing-the-workflow&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Once your workflow is set up, any push to the main branch will trigger the GitHub Actions workflow. Keep an eye on the Actions tab in your GitHub repository to monitor the progress and results.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;publish-docker-image-public-on-github-package-with-github-actions&#x2F;github-actions-run-result.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;exploring-the-published-docker-image&quot;&gt;Exploring the Published Docker Image&lt;a class=&quot;zola-anchor&quot; href=&quot;#exploring-the-published-docker-image&quot; aria-label=&quot;Anchor link for: exploring-the-published-docker-image&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Visit the GitHub Package page to view details about your published Docker image, including tags and labels.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;publish-docker-image-public-on-github-package-with-github-actions&#x2F;how-to-check-where-package-is-published.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;making-your-package-public&quot;&gt;Making Your Package Public&lt;a class=&quot;zola-anchor&quot; href=&quot;#making-your-package-public&quot; aria-label=&quot;Anchor link for: making-your-package-public&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Before pulling the image publicly, you need to make sure your GitHub Package is set to public. Easily change the visibility in the package settings.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;publish-docker-image-public-on-github-package-with-github-actions&#x2F;github-package-details.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Navigate to the settings, locate the option to change visibility, and switch it to public.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;publish-docker-image-public-on-github-package-with-github-actions&#x2F;github-package-settings.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pulling-the-image&quot;&gt;Pulling the Image&lt;a class=&quot;zola-anchor&quot; href=&quot;#pulling-the-image&quot; aria-label=&quot;Anchor link for: pulling-the-image&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Once your package is public, pulling the image becomes straightforward. Use the following Docker command, replacing &lt;code&gt;&amp;lt;username&amp;gt;&lt;&#x2F;code&gt;, &lt;code&gt;&amp;lt;repository&amp;gt;&lt;&#x2F;code&gt;, and &lt;code&gt;&amp;lt;tag&amp;gt;&lt;&#x2F;code&gt; with your specific details:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; pull ghcr.io&#x2F;&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;username&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;repository&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;:&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;tag&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For instance, pulling the &lt;code&gt;ghcr.io&#x2F;thaitype&#x2F;spy-reverse-proxy:main&lt;&#x2F;code&gt; image would look like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; pull ghcr.io&#x2F;thaitype&#x2F;spy-reverse-proxy:main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can also see the &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;spy-proxy&#x2F;releases&#x2F;tag&#x2F;v0.0.0&quot;&gt;full example repo here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Feel free to adapt the workflow and Docker image tags to align with your versioning strategy and project requirements.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;in-summary&quot;&gt;In Summary&lt;a class=&quot;zola-anchor&quot; href=&quot;#in-summary&quot; aria-label=&quot;Anchor link for: in-summary&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Congratulations! You&#x27;ve successfully set up GitHub Actions to publish your Docker images on GitHub Package. This seamless integration provides a convenient way to manage your images within the GitHub ecosystem. If you ever need to update your images or adopt a different versioning strategy, you can easily modify the workflow to suit your needs.&lt;&#x2F;p&gt;
&lt;p&gt;Thank you for joining us on this GitHub Actions journey. We hope this guide enhances your understanding of Docker image publishing and GitHub Package integration. Happy coding!&lt;&#x2F;p&gt;
&lt;p&gt;Happy coding, and until next time!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Resolving Docker Multi-stage Build Errors on GitHub Actions</title>
		<published>2024-02-01T00:00:00+00:00</published>
		<updated>2024-02-01T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/resolving-docker-multi-stage-build-errors-on-github-actions/" type="text/html"/>
		<id>https://thadaw.com/posts/resolving-docker-multi-stage-build-errors-on-github-actions/</id>
		<content type="html">&lt;p&gt;Setting up a CI&#x2F;CD pipeline with multi-stage Docker builds on GitHub Actions can be a powerful way to automate your workflow. However, you may encounter challenges, as I recently did, when building a Docker image using multi-stage builds and GitHub Actions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-problem&quot; aria-label=&quot;Anchor link for: the-problem&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;The issue surfaced when I attempted to build a Docker image with multi-stage builds using the &lt;code&gt;pnpm&lt;&#x2F;code&gt; package manager. The problem is not related to pnpm itself; instead, I utilized an example from the pnpm documentation for multi-stage builds. The error that emerged during the Docker image build process, seemingly tied to pnpm, was actually rooted in the Dockerfile&#x27;s implementation of multi-stage builds. The error message specifically highlighted an inconsistency in the cache key calculation, leading to confusion and the need for further investigation.&lt;&#x2F;p&gt;
&lt;p&gt;The root cause of the issue lies in the &lt;code&gt;Dockerfile&lt;&#x2F;code&gt;, particularly during the implementation of multi-stage builds and the integration of the pnpm package manager. For reference, the approach was inspired by &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pnpm.io&#x2F;docker#example-1-build-a-bundle-in-a-docker-container&quot;&gt;the official documentation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dockerfile&quot; class=&quot;language-dockerfile z-code&quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; node:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;20-slim&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;AS&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;base&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;PNPM_HOME=&lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;pnpm&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;PATH=&lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;$PNPM_HOME:$PATH&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;corepack enable
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; . &#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; base &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;AS&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;prod-deps&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;--mount=type=cache,id=pnpm,target=&#x2F;pnpm&#x2F;store pnpm install --prod --frozen-lockfile
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; base &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;AS&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;build&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;--mount=type=cache,id=pnpm,target=&#x2F;pnpm&#x2F;store pnpm install --frozen-lockfile
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpm run build
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; base
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;prod-deps&lt;&#x2F;span&gt; &#x2F;app&#x2F;node_modules &#x2F;app&#x2F;node_modules
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;build&lt;&#x2F;span&gt; &#x2F;app&#x2F;dist &#x2F;app&#x2F;dist
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;EXPOSE &lt;&#x2F;span&gt;8000
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-dockerfile&quot;&gt;CMD &lt;&#x2F;span&gt;[ &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;pnpm&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;start&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; ]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This section of the Dockerfile, influenced by the recommended practices outlined in the official &lt;code&gt;pnpm&lt;&#x2F;code&gt; documentation, initiates the build process. Despite following the prescribed steps, an unforeseen error arose during the GitHub Actions workflow, prompting the need for investigation and resolution.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;github-actions-workflow&quot;&gt;GitHub Actions Workflow&lt;a class=&quot;zola-anchor&quot; href=&quot;#github-actions-workflow&quot; aria-label=&quot;Anchor link for: github-actions-workflow&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;The GitHub Actions workflow responsible for building and pushing the Docker image looked like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Build and push Docker image&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;docker&#x2F;build-push-action@v5&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-decimal z-yaml&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-yaml&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The encountered error was as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;buildx failed with: ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref 8abab386-ee6f-4a46-817c-c1639873e713::8skhbm74dq1epjac59datwfm4: &amp;quot;...&amp;quot;: not found
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;solution-1-consolidating-multi-stage-builds&quot;&gt;Solution 1: Consolidating Multi-Stage Builds&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution-1-consolidating-multi-stage-builds&quot; aria-label=&quot;Anchor link for: solution-1-consolidating-multi-stage-builds&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;One approach to resolve this issue is to consolidate the multi-stage build into a single stage:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dockerfile&quot; class=&quot;language-dockerfile z-code&quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; base &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;AS&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;build&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;--mount=type=cache,id=pnpm,target=&#x2F;pnpm&#x2F;store pnpm install --frozen-lockfile
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpm run build
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Ensure `&amp;quot;type&amp;quot;: &amp;quot;module&amp;quot;` is set in package.json
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;build&lt;&#x2F;span&gt; &#x2F;app&#x2F;package.json &#x2F;app&#x2F;package.json
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Production dependencies
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;build&lt;&#x2F;span&gt; &#x2F;app&#x2F;node_modules &#x2F;app&#x2F;node_modules
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Application
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;build&lt;&#x2F;span&gt; &#x2F;app&#x2F;dist &#x2F;app
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, be cautious as this modification might lead to another error:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Error: buildx failed with: ERROR: local cache importer requires src
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;solution-2-modifying-github-actions-workflow&quot;&gt;Solution 2: Modifying GitHub Actions Workflow&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution-2-modifying-github-actions-workflow&quot; aria-label=&quot;Anchor link for: solution-2-modifying-github-actions-workflow&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;!-- I&#x27;ve found that the documentation for the `docker&#x2F;build-push-action` shown in here [docker&#x2F;build-push-action](https:&#x2F;&#x2F;github.com&#x2F;docker&#x2F;build-push-action&#x2F;tree&#x2F;v5.1.0?tab=readme-ov-file#inputs) provides that we can change the cache mechanism by adding `cache-from` e.g., `type=local,src=path&#x2F;to&#x2F;dir`
, and I&#x27;ve found that in the [List of external cache sources](https:&#x2F;&#x2F;docs.docker.com&#x2F;engine&#x2F;reference&#x2F;commandline&#x2F;buildx_build&#x2F;#cache-from) show `gha` (Github Actions Cache) for building docker. 

To address the additional error, modify the GitHub Actions workflow by adding `cache-from`: --&gt;
&lt;p&gt;In the pursuit of resolving the encountered error, I delved into the documentation for the &lt;strong&gt;&lt;code&gt;docker&#x2F;build-push-action&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;, available at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;docker&#x2F;build-push-action&#x2F;tree&#x2F;v5.1.0?tab=readme-ov-file#inputs&quot;&gt;docker&#x2F;build-push-action&lt;&#x2F;a&gt;. Here, I discovered a valuable configuration option called &lt;strong&gt;&lt;code&gt;cache-from&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; that allows us to tweak the cache mechanism. For example, we can employ &lt;strong&gt;&lt;code&gt;type=local,src=path&#x2F;to&#x2F;dir&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; to change the caching strategy.&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, exploring the &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.docker.com&#x2F;engine&#x2F;reference&#x2F;commandline&#x2F;buildx_build&#x2F;#cache-from&quot;&gt;List of external cache sources&lt;&#x2F;a&gt; revealed the use of &lt;strong&gt;&lt;code&gt;gha&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; (Github Actions Cache) as a viable option for Docker builds within the GitHub Actions environment.&lt;&#x2F;p&gt;
&lt;p&gt;To mitigate the secondary error, it is recommended to enhance the GitHub Actions workflow by incorporating the &lt;strong&gt;&lt;code&gt;cache-from&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; parameter:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Build and push Docker image&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;docker&#x2F;build-push-action@v5&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-decimal z-yaml&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-yaml&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;cache-from&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;type=gha&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These solutions aim to provide a smoother experience when working with multi-stage Docker builds in GitHub Actions. Integrating these adjustments into your pipeline should help mitigate common errors, ensuring a more efficient and reliable CI&#x2F;CD process for your project.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s the full Dockerfile and GitHub Actions configuration:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dockerfile&quot; class=&quot;language-dockerfile z-code&quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; https:&#x2F;&#x2F;pnpm.io&#x2F;docker#example-1-build-a-bundle-in-a-docker-container
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; node:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;20-slim&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;As&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;base&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;PNPM_HOME=&lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;pnpm&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;PATH=&lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;$PNPM_HOME:$PATH&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;corepack enable
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node . .&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;USER &lt;&#x2F;span&gt;node
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; base &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;AS&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;build&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;--mount=type=cache,id=pnpm,target=&#x2F;pnpm&#x2F;store pnpm install --frozen-lockfile
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpm run build
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Not Natively support ARM64 (M1)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; alpine:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;3.19&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;As&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;production&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;PORT=3333
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Make sure `&amp;quot;type&amp;quot;: &amp;quot;module&amp;quot;` is set in package.json
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;build&lt;&#x2F;span&gt; &#x2F;app&#x2F;package.json &#x2F;app&#x2F;package.json
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Production dependencies
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;build&lt;&#x2F;span&gt; &#x2F;app&#x2F;node_modules &#x2F;app&#x2F;node_modules
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Application
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;build&lt;&#x2F;span&gt; &#x2F;app&#x2F;dist &#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;apk add --update --no-cache nodejs=$NODE_VERSION
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;EXPOSE &lt;&#x2F;span&gt;${PORT}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Create a group and user
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;addgroup -g 1000 node \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;    &amp;amp;&amp;amp; adduser -u 1000 -G node -s &#x2F;bin&#x2F;sh -D node
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;USER &lt;&#x2F;span&gt;node
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-dockerfile&quot;&gt;CMD &lt;&#x2F;span&gt;[ &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;node&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;app&#x2F;main.js&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; ]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and Github Actions&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;actions&#x2F;publishing-packages&#x2F;publishing-docker-images#publishing-images-to-github-packages
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Create and publish a Docker image&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Configures this workflow to run every time a change is pushed to the branch called `release`.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-constant z-language z-boolean z-yaml&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; branches: [&amp;#39;release&amp;#39;]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;branches&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;REGISTRY&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;ghcr.io&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;IMAGE_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ github.repository }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; There is a single job in this workflow. It&amp;#39;s configured to run on the latest available version of Ubuntu.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;build-and-push-image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;runs-on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;ubuntu-latest&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;permissions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;contents&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;read&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;packages&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;write&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;steps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Checkout repository&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;actions&#x2F;checkout@v4&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Uses the `docker&#x2F;login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Log in to the Container registry&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;docker&#x2F;login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;registry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ env.REGISTRY }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;username&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ github.actor }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;password&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; This step uses [docker&#x2F;metadata-action](https:&#x2F;&#x2F;github.com&#x2F;docker&#x2F;metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` &amp;quot;meta&amp;quot; allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Extract metadata (tags, labels) for Docker&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;meta&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;docker&#x2F;metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;images&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ env.REGISTRY }}&#x2F;${{ env.IMAGE_NAME }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; This step uses the `docker&#x2F;build-push-action` action to build the image, based on your repository&amp;#39;s `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; It uses the `context` parameter to define the build&amp;#39;s context as the set of files located in the specified path. For more information, see &amp;quot;[Usage](https:&#x2F;&#x2F;github.com&#x2F;docker&#x2F;build-push-action#usage)&amp;quot; in the README of the `docker&#x2F;build-push-action` repository.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; It uses the `tags` and `labels` parameters to tag and label the image with the output from the &amp;quot;meta&amp;quot; step.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Build and push Docker image&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;docker&#x2F;build-push-action@v5&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-decimal z-yaml&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-yaml&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;tags&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ steps.meta.outputs.tags }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;labels&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ steps.meta.outputs.labels }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;cache-from&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;type=gha&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can also see the &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;spy-proxy&#x2F;releases&#x2F;tag&#x2F;v0.0.0&quot;&gt;full example repo here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;discussion&quot;&gt;&lt;strong&gt;Discussion&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#discussion&quot; aria-label=&quot;Anchor link for: discussion&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;investigating-multi-stage-builds&quot;&gt;&lt;strong&gt;Investigating Multi-Stage Builds&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#investigating-multi-stage-builds&quot; aria-label=&quot;Anchor link for: investigating-multi-stage-builds&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;In dissecting the encountered challenges during the Docker image build process, it became evident that the initial error, seemingly attributed to the &lt;strong&gt;&lt;code&gt;pnpm&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; package manager, was, in fact, a consequence of the implementation of multi-stage builds in the Dockerfile. The chosen approach drew inspiration from the official &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pnpm.io&#x2F;docker#example-1-build-a-bundle-in-a-docker-container&quot;&gt;pnpm documentation&lt;&#x2F;a&gt;. This revelation clarified that the issue did not originate from &lt;strong&gt;&lt;code&gt;pnpm&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; itself but rather from nuances in the Dockerfile structure.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;navigating-dockerfile-complexity&quot;&gt;&lt;strong&gt;Navigating Dockerfile Complexity&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#navigating-dockerfile-complexity&quot; aria-label=&quot;Anchor link for: navigating-dockerfile-complexity&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;The Dockerfile&#x27;s multi-stage build, designed to optimize the image creation process, unintentionally introduced complexities that led to an error in cache key calculation. Recognizing the root cause and understanding the intricacies of multi-stage builds proved pivotal in devising effective solutions.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;unveiling-github-actions-insights&quot;&gt;&lt;strong&gt;Unveiling GitHub Actions Insights&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#unveiling-github-actions-insights&quot; aria-label=&quot;Anchor link for: unveiling-github-actions-insights&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;In the quest for resolution, a deep dive into the documentation for the &lt;strong&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;docker&#x2F;build-push-action&#x2F;tree&#x2F;v5.1.0?tab=readme-ov-file#inputs&quot;&gt;docker&#x2F;build-push-action&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; shed light on valuable configuration options. The discovery of the &lt;strong&gt;&lt;code&gt;cache-from&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; parameter provided an avenue to refine the caching strategy, offering insights into optimizing the GitHub Actions workflow for Docker image builds.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solutions-explored&quot;&gt;&lt;strong&gt;Solutions Explored&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#solutions-explored&quot; aria-label=&quot;Anchor link for: solutions-explored&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;solution-1-consolidating-multi-stage-builds-1&quot;&gt;&lt;strong&gt;Solution 1: Consolidating Multi-Stage Builds&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution-1-consolidating-multi-stage-builds-1&quot; aria-label=&quot;Anchor link for: solution-1-consolidating-multi-stage-builds-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;The first solution involved consolidating the multi-stage build into a single stage, modifying the Dockerfile structure. However, this adjustment posed the risk of triggering another error, necessitating a careful balance between optimization and potential pitfalls.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;solution-2-refining-github-actions-workflow&quot;&gt;&lt;strong&gt;Solution 2: Refining GitHub Actions Workflow&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution-2-refining-github-actions-workflow&quot; aria-label=&quot;Anchor link for: solution-2-refining-github-actions-workflow&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;The second solution focused on refining the GitHub Actions workflow by leveraging insights from the &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;docker&#x2F;build-push-action&#x2F;tree&#x2F;v5.1.0?tab=readme-ov-file#inputs&quot;&gt;docker&#x2F;build-push-action documentation&lt;&#x2F;a&gt;. The introduction of the &lt;strong&gt;&lt;code&gt;cache-from&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; parameter, particularly using &lt;strong&gt;&lt;code&gt;type=gha&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; (GitHub Actions Cache), aimed to enhance the caching strategy, addressing the secondary error and offering a more stable foundation for Docker image building within the GitHub Actions environment.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;strong&gt;Conclusion&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;In navigating the complexities of multi-stage Docker builds and GitHub Actions, this exploration has illuminated the importance of meticulous configuration and adaptation. While inspired by best practices from the &lt;strong&gt;&lt;code&gt;pnpm&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; documentation, it is crucial to recognize that each project&#x27;s unique context may demand tailored solutions.&lt;&#x2F;p&gt;
&lt;p&gt;The refinement of the Dockerfile structure and the optimization of the GitHub Actions workflow showcase the iterative nature of development. By embracing insights from documentation and understanding the tools at our disposal, we can pave the way for smoother CI&#x2F;CD pipelines and more resilient Docker image builds.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Readable unit testing for local timezone using dayjs</title>
		<published>2024-01-09T00:00:00+00:00</published>
		<updated>2024-01-09T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/readable-unit-testing-for-local-timezone-using-dayjs/" type="text/html"/>
		<id>https://thadaw.com/posts/readable-unit-testing-for-local-timezone-using-dayjs/</id>
		<content type="html">&lt;p&gt;Unit testing is a crucial aspect of software development, and when it comes to testing functionality dependent on time and timezones, having readable and effective tests is essential.&lt;&#x2F;p&gt;
&lt;p&gt;In this blog post, we&#x27;ll explore how to perform unit testing for local timezones using TypeScript and &lt;code&gt;Dayjs&lt;&#x2F;code&gt;. We&#x27;ll walk through a practical example involving a function to identify the state of a resource based on its environment and the current time. Additionally, we&#x27;ll introduce a &lt;code&gt;Dayjs&lt;&#x2F;code&gt; timezone helper to facilitate seamless testing across different timezones.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;example-code&quot;&gt;Example Code&lt;a class=&quot;zola-anchor&quot; href=&quot;#example-code&quot; aria-label=&quot;Anchor link for: example-code&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s start by examining the core function responsible for identifying the state of a resource:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * Identify the state of the resource
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * &lt;span class=&quot;z-storage z-type z-class z-jsdoc&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tag z-jsdoc&quot;&gt;@&lt;&#x2F;span&gt;param&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-jsdoc&quot;&gt;resource&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * &lt;span class=&quot;z-storage z-type z-class z-jsdoc&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tag z-jsdoc&quot;&gt;@&lt;&#x2F;span&gt;param&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-jsdoc&quot;&gt;date&lt;&#x2F;span&gt; - Passing date for testing purpose
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * &lt;span class=&quot;z-storage z-type z-class z-jsdoc&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tag z-jsdoc&quot;&gt;@&lt;&#x2F;span&gt;returns&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;identifyResourceState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Date&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Date&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;scaled_up&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;scaled_down&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;   * If the resource is not `dev`, the state is scaled up.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;   &lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;env&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-ts&quot;&gt;!==&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;dev&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;scaled_up&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;   * Time between 8:00 UTC+7 to 19:00 UTC+7, the state is scaled up.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;   * Otherwise, the state is scaled down.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;   &lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;hour&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;getUTCHours&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;hour&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;hour&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;scaled_up&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;scaled_down&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;dayjs-timezone-helper&quot;&gt;Dayjs Timezone helper&lt;a class=&quot;zola-anchor&quot; href=&quot;#dayjs-timezone-helper&quot; aria-label=&quot;Anchor link for: dayjs-timezone-helper&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;To enhance the testing process, we introduce a Dayjs helper to handle timezones effectively:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Dayjs helper&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;dayjs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;dayjs&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;utc&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;dayjs&#x2F;plugin&#x2F;utc&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;timezone&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;dayjs&#x2F;plugin&#x2F;timezone&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;dayjs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;extend&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;utc&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;dayjs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;extend&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;timezone&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createDateFromTimezone&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-optional z-ts&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;dayjs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ConfigType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;timezone&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-optional z-ts&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-optional z-ts&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;dayjs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ConfigType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;dayjsFromTimezone&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;timezone&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toDate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;dayjsFromTimezone&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-optional z-ts&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;dayjs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ConfigType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;timezone&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-optional z-ts&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;dayjs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;tz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;timezone&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;utc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;a class=&quot;zola-anchor&quot; href=&quot;#implementation&quot; aria-label=&quot;Anchor link for: implementation&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Now, let&#x27;s look at how we can effectively test the &lt;code&gt;identifyResourceState&lt;&#x2F;code&gt; function using our Dayjs timezone helpe&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;test&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;vitest&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;createDateFromTimezone&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.&#x2F;dayjs&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;identifyResourceState&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.&#x2F;identify-resource-state&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;createBangkokDate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createDateFromTimezone&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Asia&#x2F;Bangkok&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;dateString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;2023-12-15&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;identifyResourceState for dev&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;expect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;identifyResourceState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;dev&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createBangkokDate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dateString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 06:00&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;scaled_down&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;expect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;identifyResourceState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;dev&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createBangkokDate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dateString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 09:00&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;scaled_up&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;expect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;identifyResourceState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;dev&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createBangkokDate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dateString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 12:00&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;scaled_up&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;expect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;identifyResourceState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;dev&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createBangkokDate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dateString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 20:00&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;scaled_down&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;identifyResourceState for prod&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;expect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;identifyResourceState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;prod&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createBangkokDate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dateString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 06:00&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;scaled_up&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;expect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;identifyResourceState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;prod&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createBangkokDate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dateString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 09:00&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;scaled_up&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;expect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;identifyResourceState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;prod&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createBangkokDate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dateString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 12:00&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;scaled_up&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;expect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;identifyResourceState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;prod&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createBangkokDate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;dateString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 20:00&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;scaled_up&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this example, we&#x27;ve provided a clear introduction, added comments, and organized the content for better readability. Feel free to adapt this to suit your preferences and context!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Nammatham v2.x: A Type-Safe Evolution with Improved Dependency Injection</title>
		<published>2024-01-06T00:00:00+00:00</published>
		<updated>2024-01-06T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/nammatham-v2x-a-type-safe-evolution-with-improved-dependency-injection/" type="text/html"/>
		<id>https://thadaw.com/posts/nammatham-v2x-a-type-safe-evolution-with-improved-dependency-injection/</id>
		<content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction:&lt;a class=&quot;zola-anchor&quot; href=&quot;#introduction&quot; aria-label=&quot;Anchor link for: introduction&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;When developing Nammatham v1.x, I acknowledged that the experience was somewhat limited. The integration with Dependency Injection (Inversify) was overly complex, leading to constraints in scalability and extensibility. 🥲&lt;&#x2F;p&gt;
&lt;p&gt;Nammatham v2.x, on the other hand, underwent a complete overhaul! 🥳 We eliminated the tight coupling with Inversify and reduced the reliance on decorators, making it more type-safe. This version now supports easier expansion, steering away from the limitations of the past.&lt;&#x2F;p&gt;
&lt;p&gt;For instance, it seamlessly integrates with Express for Azure Functions Dev, providing an alternative to the official approach, which suffered from slow startup times and the need to compile to JS before debugging. Additionally, libraries like tRPC are now compatible and contribute to the overall improved developer experience. 🤗&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-to-the-point&quot;&gt;Getting to the Point:&lt;a class=&quot;zola-anchor&quot; href=&quot;#getting-to-the-point&quot; aria-label=&quot;Anchor link for: getting-to-the-point&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;After successfully proving the concept with Nammatham v2.x, supporting Azure Functions v4 models with enhanced type safety and developer experience, a new challenge arose. The existing production code of v1.x heavily relied on Inversify&#x27;s robust container. How could we address this without the need for a complete code rewrite? 🤩&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;The Solution:&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-solution&quot; aria-label=&quot;Anchor link for: the-solution&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;We decided to create helper functions that are type-safe and assist in resolving service dependencies for Inversify. This approach allows for a graceful migration from v1.x to v2.x without the need to overhaul the existing codebase. It&#x27;s a work in progress (all libraries are currently in alpha stage with rigorous testing ongoing), but it holds promise for a smooth transition, as depicted in the image below. 👇👇&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;nammatham-v2x-a-type-safe-evolution-with-improved-dependency-injection&#x2F;compare.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For those interested in the code, feel free to explore and give it a star if you find it useful! 📣&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Nammatham: https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;nammatham&lt;&#x2F;li&gt;
&lt;li&gt;di-extra: https:&#x2F;&#x2F;github.com&#x2F;thaitype&#x2F;di-extra&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;P.S. Nammatham is a TypeScript library designed to facilitate the development of serverless functions, such as Azure Functions and others in the future (assuming contributions are made 🙏).&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>เขียน Concurrency ใน TypeScript ด้วย Promise allSettled</title>
		<published>2023-12-05T00:00:00+00:00</published>
		<updated>2023-12-05T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/concurrency-in-typescript-promise-all-settled/" type="text/html"/>
		<id>https://thadaw.com/posts/concurrency-in-typescript-promise-all-settled/</id>
		<content type="html">&lt;p&gt;การทำงานแบบ concurrency หรือการทำงานพร้อมกันหลายๆ งานที่ต้องใช้เวลานานใน TypeScript สามารถทำได้ง่ายๆ ด้วย &lt;code&gt;Promise.allSettled&lt;&#x2F;code&gt; ซึ่งช่วยให้เราสามารถรัน Promise หลายๆ ตัวพร้อมกันและรับผลลัพธ์ทั้งหมดได้ไม่ว่า Promise ตัวไหนจะสำเร็จหรือไม่สำเร็จก็ตาม&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;concurrency-in-typescript-promise-all-settled&#x2F;concurrent-example-ts.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;taw-yaangkaaraichngaan&quot;&gt;ตัวอย่างการใช้งาน&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangkaaraichngaan&quot; aria-label=&quot;Anchor link for: taw-yaangkaaraichngaan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ในตัวอย่างนี้ เราจะมีฟังก์ชัน main ที่ใช้ &lt;code&gt;Promise.allSettled&lt;&#x2F;code&gt; เพื่อรัน Promise หลายๆ ตัวที่แทนงานที่ต้องใช้เวลานาน เช่นการเรียกใช้ API, การดึงข้อมูลจากฐานข้อมูล, หรือการประมวลผลข้อมูลที่มีขนาดใหญ่&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-async z-ts&quot;&gt;async&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;   &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; 1. สร้าง Reference ของ Promise ที่เป็น Array ว่างๆ ไว้ก่อน&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;promises&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Promise&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; 2. วนลูปเรียกใช้ longRunningTask 5 ครั้ง โดยที่ไม่ต้องใช้ Await เพื่อให้แต่ละ Task ทำงานพร้อมกัน&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-loop z-ts&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-increment z-ts&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;promises&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;longRunningTask&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; 3. รอให้ทุก Task ทำงานเสร็จ&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;results&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-promise z-ts&quot;&gt;Promise&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;allSettled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;promises&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;--------------------------------------------------&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;All tasks finished&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;   &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; 4. วนลูปเรียกใช้ console.log แสดงผลลัพธ์ที่ได้จากทุก Task ที่เสร็จสิ้น&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-loop z-ts&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt;of&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;results&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;status&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-ts&quot;&gt;===&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;fulfilled&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Task &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; took &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;value&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; seconds&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;else&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Task &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; failed with error: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;reason&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-increment z-ts&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;kaarthamngaankh-ng-promise-allsettled&quot;&gt;การทำงานของ Promise.allSettled&lt;a class=&quot;zola-anchor&quot; href=&quot;#kaarthamngaankh-ng-promise-allsettled&quot; aria-label=&quot;Anchor link for: kaarthamngaankh-ng-promise-allsettled&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เมื่อเรียกใช้ &lt;code&gt;Promise.allSettled&lt;&#x2F;code&gt; จะได้ผลลัพธ์เป็น &lt;code&gt;PromiseSettledResult&amp;lt;T&amp;gt;[]&lt;&#x2F;code&gt; โดย T คือประเภทข้อมูลที่ Promise ส่งกลับ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;results&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-promise z-ts&quot;&gt;Promise&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;allSettled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;promises&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; PromiseSettledResult&amp;lt;number&amp;gt;[]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;โค้ดนี้ใช้ interface PromiseFulfilledResult และ PromiseRejectedResult ในการบอกสถานะของ Promise ว่าสำเร็จหรือไม่สำเร็จ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-interface z-ts&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-ts&quot;&gt;PromiseFulfilledResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;fulfilled&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-interface z-ts&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-ts&quot;&gt;PromiseRejectedResult&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;rejected&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;reason&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;PromiseSettledResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;PromiseFulfilledResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;PromiseRejectedResult&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;สังเกตุในโค๊ดตรงนี้จะเห็นได้ว่า &lt;code&gt;result&lt;&#x2F;code&gt; จะมี type เป็น &lt;code&gt;PromiseSettledResult&amp;lt;number&amp;gt;&lt;&#x2F;code&gt;
ดังนั้นเราสามารถ guard type (ลดความเป็นไปได้ของ Type) นั่นคือ&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ถ้ามี &lt;code&gt;status&lt;&#x2F;code&gt; เท่ากับ &lt;code&gt;&quot;fulfilled&quot;&lt;&#x2F;code&gt; หมายความว่า TypeScript จะรู้ว่ามันคือ Type &lt;code&gt;PromiseFulfilledResult&amp;lt;number&amp;gt;&lt;&#x2F;code&gt; อัตโนมัติ ซึ่งก็ึคือมี key &lt;code&gt;value&lt;&#x2F;code&gt; ที่มี Type เป็น &lt;code&gt;number&lt;&#x2F;code&gt; นั่นเอง&lt;&#x2F;li&gt;
&lt;li&gt;แต่ถ้ามี &lt;code&gt;status&lt;&#x2F;code&gt; ไม่เท่ากับ &lt;code&gt;&quot;fulfilled&quot;&lt;&#x2F;code&gt; (Else Condition) หมายความว่า TypeScript จะรู้ว่ามันคือ Type &lt;code&gt;PromiseRejectedResult&amp;lt;number&amp;gt;&lt;&#x2F;code&gt; อัตโนมัติ (เพราะมีโอกาสแค่ 2 แบบ ถ้าไม่ใช่แบบแรก ก็จะเป็นแบบที่ 2 ทันที)  ซึ่งก็ึคือมี key &lt;code&gt;reason&lt;&#x2F;code&gt; ที่มี Type เป็น &lt;code&gt;any&lt;&#x2F;code&gt; นั่นเอง&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;... Loop in `results` array then....&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;status&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-ts&quot;&gt;===&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;fulfilled&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Task &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; took &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;value&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; seconds&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;else&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Task &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; failed with error: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;reason&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;taw-yaangkh-ngfangkchanthiirannaan&quot;&gt;ตัวอย่างของฟังก์ชันที่รันนาน&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangkh-ngfangkchanthiirannaan&quot; aria-label=&quot;Anchor link for: taw-yaangkh-ngfangkchanthiirannaan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ในตัวอย่างนี้ เราจำลองการทำงานที่ใช้เวลานานด้วยฟังก์ชัน longRunningTask ที่ทำการจำลองการทำงานและผลลัพธ์ที่สามารถเป็นไปได้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;longRunningTask&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;taskId&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;minDurationSec&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;maxDurationSec&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Promise&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;minDuration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;minDurationSec&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;maxDuration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;maxDurationSec&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;delay&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-math z-ts&quot;&gt;Math&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-math z-ts&quot;&gt;ceil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-math z-ts&quot;&gt;Math&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-math z-ts&quot;&gt;floor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-math z-ts&quot;&gt;Math&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-math z-ts&quot;&gt;random&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;maxDuration&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;minDuration&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;        &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;minDuration&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;        &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Task &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;taskId&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; started, will take &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;delay&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; seconds&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;currentTime&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;interval&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;setInterval&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;currentTime&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-compound z-ts&quot;&gt;+=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Task &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;taskId&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; in progress, current time: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;currentTime&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; seconds&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Promise&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;resolve&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;reject&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;setTimeout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;clearInterval&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;interval&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-math z-ts&quot;&gt;Math&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-math z-ts&quot;&gt;random&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;span class=&quot;z-meta z-delimiter z-decimal z-period z-ts&quot;&gt;.&lt;&#x2F;span&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Task &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;taskId&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; failed&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;reject&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Task &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;taskId&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; failed&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;else&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Task &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;taskId&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; finished&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;resolve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;delay&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;delay&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ผลลัพธ์จะแสดงข้อความเกี่ยวกับการทำงานที่รันนานและผลลัพธ์ของแต่ละงานที่สำเร็จหรือไม่สำเร็จ&lt;&#x2F;p&gt;
&lt;p&gt;ด้วยการใช้ &lt;code&gt;Promise.allSettled&lt;&#x2F;code&gt; ใน TypeScript เราสามารถทำงาน concurrency ได้อย่างมีประสิทธิภาพและปรับให้เหมาะกับลำดับการทำงานที่ต้องการในแต่ละบล็อกของโปรแกรมของเราได้อย่างง่ายดาย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;taw-yaangkaarthamngaankh-ngopraekrm&quot;&gt;ตัวอย่างการทำงานของโปรแกรม&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangkaarthamngaankh-ngopraekrm&quot; aria-label=&quot;Anchor link for: taw-yaangkaarthamngaankh-ngopraekrm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 1 started, will take 4 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 2 started, will take 4 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 3 started, will take 5 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 4 started, will take 4 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 5 started, will take 2 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 1 in progress, current time: 1 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 2 in progress, current time: 1 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 3 in progress, current time: 1 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 4 in progress, current time: 1 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 5 in progress, current time: 1 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 5 failed
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 1 in progress, current time: 2 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 2 in progress, current time: 2 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 3 in progress, current time: 2 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 4 in progress, current time: 2 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 1 in progress, current time: 3 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 2 in progress, current time: 3 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 3 in progress, current time: 3 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 4 in progress, current time: 3 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 1 finished
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 2 finished
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 4 failed
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 3 in progress, current time: 4 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 3 failed
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;--------------------------------------------------
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;All tasks finished
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 1 took 4 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 2 took 4 seconds
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 3 failed with error: Task 3 failed
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 4 failed with error: Task 4 failed
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Task 5 failed with error: Task 5 failed
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>สร้างตัวแปร Terraform Cloud ผ่าน JavaScript และ Axios</title>
		<published>2023-12-01T00:00:00+00:00</published>
		<updated>2023-12-01T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/create-terraform-cloud-variables-via-javascript/" type="text/html"/>
		<id>https://thadaw.com/posts/create-terraform-cloud-variables-via-javascript/</id>
		<content type="html">&lt;p&gt;การใช้งาน Terraform Cloud จะต้องใช้ User API Token เพื่อทำการจัดการ Workspace ของคุณ โดยคุณสามารถสร้าง Token ได้ที่ลิงก์ https:&#x2F;&#x2F;app.terraform.io&#x2F;app&#x2F;settings&#x2F;tokens นี้&lt;&#x2F;p&gt;
&lt;p&gt;หลังจากที่ได้ User API Token แล้ว คุณต้องมี Workspace ID เพื่อทำการเข้าถึง Workspace ที่ต้องการ โปรดทราบว่า Workspace ที่ใช้ในตัวอย่างนี้&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;create-terraform-cloud-variables-via-javascript&#x2F;get-workspace-id.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;เพื่อสร้างตัวแปรใหม่ใน Workspace โดยใช้ Workspace API ตามลิงก์ https:&#x2F;&#x2F;developer.hashicorp.com&#x2F;terraform&#x2F;cloud-docs&#x2F;api-docs&#x2F;workspace-variables คุณสามารถทำได้โดยใช้โค้ดต่อไปนี้ที่เขียนด้วย JavaScript และใช้ Axios เพื่อส่งคำขอ:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;axios&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;axios&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;workspaceId&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;ws-1z8PbLVuFdcqqqFR&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;MY-TOKEN&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-json z-ts&quot;&gt;JSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-json z-ts&quot;&gt;stringify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;data&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;type&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;vars&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;attributes&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;key&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;some_key&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;value&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;some_value&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;description&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;some description&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;category&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;terraform&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;hcl&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-false z-ts&quot;&gt;false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;sensitive&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-false z-ts&quot;&gt;false&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;post&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;url&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;https:&#x2F;&#x2F;app.terraform.io&#x2F;api&#x2F;v2&#x2F;workspaces&#x2F;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;workspaceId&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;vars&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;headers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Content-Type&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;application&#x2F;vnd.api+json&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Authorization&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Bearer &lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;data &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;data&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-trycatch z-ts&quot;&gt;try&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;response&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;axios&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-json z-ts&quot;&gt;JSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-json z-ts&quot;&gt;stringify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;response&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-trycatch z-ts&quot;&gt;catch&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;error&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;error&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;อย่าลืมแทนค่า &lt;code&gt;workspaceId&lt;&#x2F;code&gt; และ &lt;code&gt;token&lt;&#x2F;code&gt; ด้วยค่าจริงที่คุณได้รับจาก Terraform Cloud นะครับ&lt;&#x2F;p&gt;
&lt;p&gt;นอกจากนี้ยังสามารถปรับแต่งค่าต่าง ๆ ในส่วนของตัวแปรที่ต้องการสร้างตามความเหมาะสมของโปรเจคของคุณได้&lt;&#x2F;p&gt;
&lt;p&gt;สุดท้าย, หลังจากการส่งคำขอสร้างตัวแปรเสร็จสิ้น, คุณจะได้รับข้อมูลการตอบกลับที่แสดงถึงสถานะการทำงานของคำขอ&lt;&#x2F;p&gt;
&lt;p&gt;หวังว่าบทความนี้จะมีประโยชน์สำหรับการจัดการและใช้งาน Terraform Cloud ของคุณครับ!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;taw-yaangkaaraich-postman&quot;&gt;ตัวอย่างการใช้ Postman&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangkaaraich-postman&quot; aria-label=&quot;Anchor link for: taw-yaangkaaraich-postman&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;create-terraform-cloud-variables-via-javascript&#x2F;postman-test-result.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ระมัดระวัง Circular Generic Params ใน TypeScript จะทำให้การคาดเดา Type ไม่ได้</title>
		<published>2023-11-18T00:00:00+00:00</published>
		<updated>2023-11-18T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/beware-circular-generic-params-in-typescript-can-lead-to-unpredictable-types/" type="text/html"/>
		<id>https://thadaw.com/posts/beware-circular-generic-params-in-typescript-can-lead-to-unpredictable-types/</id>
		<content type="html">&lt;p&gt;บทความนี้จะพาเราสู่โลกที่ลึกลับของ TypeScript และ Generic Params ที่ทำให้โปรแกรมเมอร์เราสามารถเขียนโค้ดที่ยืดหยุ่นและมีประสิทธิภาพได้มากยิ่งขึ้น! 🚀&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;beware-circular-generic-params-in-typescript-can-lead-to-unpredictable-types&#x2F;summary.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;kaaraich-generic-params-ain-typescript&quot;&gt;การใช้ Generic Params ใน TypeScript&lt;a class=&quot;zola-anchor&quot; href=&quot;#kaaraich-generic-params-ain-typescript&quot; aria-label=&quot;Anchor link for: kaaraich-generic-params-ain-typescript&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ก่อนที่เราจะลุกไปเริ่มต้น มาเริ่มจากการเข้าใจหลักการของ Generic Params กันก่อนนะครับ ใน TypeScript, Generic Params จะช่วยให้เราสร้างโค้ดที่ใช้งานได้กับหลายประเภท โดยที่ไม่ต้องระบุประเภทนั้นๆ ในระหว่างการเขียนโค้ด&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;identity&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;arg&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;arg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ในตัวอย่างนี้ &lt;code&gt;T&lt;&#x2F;code&gt; คือ Generic Param ที่เราสามารถใช้กับประเภทใดๆ ก็ได้ โดยที่ไม่ต้องระบุประเภทไว้ล่วงหน้า&lt;&#x2F;p&gt;
&lt;p&gt;ตัวอย่างการใช้งาน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; สร้างตัวแปรแบบ string&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;stringValue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;identity&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;     ^? const stringValue: &amp;quot;Hello&amp;quot;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; สร้างตัวแปรแบบ number&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;numberValue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;identity&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;42&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;     ^? const numberValue: 42    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; สร้างตัวแปรแบบ object&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;objectValue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;identity&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;value&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;     ^? const objectValue: { key: string; }&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;kaar-infer-type-ain-function&quot;&gt;การ Infer Type ใน Function&lt;a class=&quot;zola-anchor&quot; href=&quot;#kaar-infer-type-ain-function&quot; aria-label=&quot;Anchor link for: kaar-infer-type-ain-function&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;โดยปกติแล้ว TypeScript สามารถ Infer Type จาก Function Type ได้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-interface z-ts&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-ts&quot;&gt;Context&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;trackId&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createEndpoint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TOutput&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;handler&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;params&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-return z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TOutput&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Mock type for Output Return Type&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TOutput&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เช่น ในตัวอย่างข้างบน
&lt;code&gt;handler&lt;&#x2F;code&gt; จะรับ parameter ที่เป็น handler ที่มี Type แบบนี้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;params&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;TOutput&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;โดยที่เมื่อผู้ใช้งานกำหนด Function ใน &lt;code&gt;handler&lt;&#x2F;code&gt; Return Type ของ &lt;code&gt;handler&lt;&#x2F;code&gt; ตัวนั้น ก็จะได้ Type ของ &lt;code&gt;TOutput&lt;&#x2F;code&gt; เหมือนกัน&lt;&#x2F;p&gt;
&lt;p&gt;ในตัวอย่างนี้ มีการส่ง function เข้าไปใน &lt;code&gt;handler&lt;&#x2F;code&gt; params โดยมี Return Type เป็น &lt;code&gt;{ name: string }&lt;&#x2F;code&gt;
ดังนั้น &lt;code&gt;createEndpoint&lt;&#x2F;code&gt; ก็สามารถ infer Type ออกมาได้เหมือนกับ Return Type ของ &lt;code&gt;handler&lt;&#x2F;code&gt; เช่นเดียวกัน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;myEndpoint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createEndpoint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;helloWorld&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;context&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Running on context id: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;helloWorld&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เมื่อเราเช็ค Type ของ &lt;code&gt;myEndpoint&lt;&#x2F;code&gt; ดูก็พบว่า Type จะตรงกับ Return Type กับ Handler เลย&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;myEndpoint&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ^? const myEndpoint: {&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;     name: string;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; }&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;kaareriiykaichngaanaebb-circular&quot;&gt;การเรียกใช้งานแบบ Circular&lt;a class=&quot;zola-anchor&quot; href=&quot;#kaareriiykaichngaanaebb-circular&quot; aria-label=&quot;Anchor link for: kaareriiykaichngaanaebb-circular&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;แต่มีข้อควรระวังในการใช้ Generic Params เวลาที่เราเรียกใช้งานแบบ Circular เช่นตัวอย่างนี้ &lt;code&gt;TOutput&lt;&#x2F;code&gt; เป็น Generic Params ที่จะ Infer Type มาจาก Return Type ของ &lt;code&gt;handler&lt;&#x2F;code&gt; ออกมา&lt;&#x2F;p&gt;
&lt;p&gt;ตัวอย่างการเรียก Generic Params แบบ Circular&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;createEndpoint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TOutput&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;handler&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;params&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; เพิ่ม TOutput ลงไปเพิ่มหลังจากที่ Infer Type Return แล้ว&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TOutput&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Context&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-return z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TOutput&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Mock type for Output Return Type&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TOutput&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;... const myEndpoint = createEndpoint(...)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;myEndpoint&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ^? const myEndpoint: unknown&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;โดยที่เมื่อเราพยายามใส่ &lt;code&gt;TOutput&lt;&#x2F;code&gt; ลงไปใน Type ของ &lt;code&gt;handler&lt;&#x2F;code&gt; ที่แท้จริงแล้ว Type จะมาจาก Return Type แล้ว Infer ออกมา แต่กลับ มีการเรียก Type Infer จาก Params ของ &lt;code&gt;handler&lt;&#x2F;code&gt; ด้วย กลับกลายเป็นว่า TypeScript ไม่สามารถคาดเดา Type ที่ถูกต้องกันได้ เพราะต่างฝ่ายต่างเรียกหากันเอง จึงทำให้ &lt;code&gt;myEndpoint&lt;&#x2F;code&gt; มีค่าเป็น &lt;code&gt;unknown&lt;&#x2F;code&gt; ไปเลย&lt;&#x2F;p&gt;
&lt;p&gt;หวังว่าจะเป็นประโยชน์นะครับ แล้วพบกันใหม่ สวัสดีครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thamaimthuengeriiykwaa-circular-problem&quot;&gt;ทำไมถึงเรียกว่า Circular Problem&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamaimthuengeriiykwaa-circular-problem&quot; aria-label=&quot;Anchor link for: thamaimthuengeriiykwaa-circular-problem&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;ผมได้อธิบายไว้ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.facebook.com&#x2F;photo?fbid=827932616003068&amp;amp;set=a.486562490140084&quot;&gt;Post ของ Facebook ของเพจ ThaiType&lt;&#x2F;a&gt;
และลูกเพจ คุณ Kasama Chenkaow ได้อธิบายได้ดีเลยทีเดียว และผมได้อธิบายว่าถึงผมใช้คำว่า Circular Problem&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;beware-circular-generic-params-in-typescript-can-lead-to-unpredictable-types&#x2F;why-circular.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;โดยส่วนตัวผมคิดว่าเรียกกำหนด &lt;code&gt;createEndpoint&lt;&#x2F;code&gt; แบบไม่ระบุ Generic Params มันจะ Infer Generic Type มาจาก Param ที่ใส่เข้าไปใน Function ถูกมั้ยครับ&lt;&#x2F;p&gt;
&lt;p&gt;ดังนั้นเราก็จึงสามารถระบุ Generic Type ของ &lt;code&gt;createEndpoint&lt;&#x2F;code&gt; โดยการใส่ให้มัน เช่น &lt;code&gt;createEndpoint&amp;lt;{ title: string }&amp;gt;&lt;&#x2F;code&gt; แต่ถ้า Param ที่ใส่มา Type ไม่ตรง TypeScript ก็ TypeError ได้ ซึ่งก็เป็นเรื่องปกติ
ทีนี้มาดูสาเหตุที่ผลถึงเรียกมันว่า Circular Issues กันครับ (ผมอาจจะเรียกไม่ถูกก็ได้ นะครับ ถ้าผิดก็ขออภัย) แต่ถ้าเราดูจากลำดับการ Infer Type ของ Generic Params เราจะเห็นว่า มันเป็นลำดับ 1,2,3 ตามในรูป ใช่มั้ยครับ&lt;&#x2F;p&gt;
&lt;p&gt;ในข้อที่ 3. มันเกิด Conflict เนื่องด้วยมาจากที่มาจากการ Infer Type มาจากคนละ Source กัน&lt;&#x2F;p&gt;
&lt;p&gt;ในข้อ 3. Infer Type จะมาจากการกำหนด Type ที่รู้ล่วงหน้ามาก่อนแล้วว่าจะมี Type อะไรอยู่
ส่วนข้อ 2. จะ Infer Type มาจากการที่เราใส่ Params ลงไปใน function ของ Generics เพื่อให้ TypeScript คาดเดา Type&lt;&#x2F;p&gt;
&lt;p&gt;จากเหตุผลที่ว่า ทั้งข้อ 2,3 มาจาก source คนทิศทางกัน และในเมื่อมันมาบนจบกัน ซึ่งคือข้อ 2 จะ infer ไปหาข้อ 3. และข้อ 3. ก็จะ infer ไปหาข้อ 2.(ในกรณีที่ไม่ได้ระบุ Generic Type ให้กับ function ล่วงหน้าไว้ก่อน เช่น &lt;code&gt;createEndpoint(..)&lt;&#x2F;code&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;จากเหตุการดังกล่าวทำให้เกิดสิ่งที่เรียกว่า Circular Generic Params (จริงๆ อาจจะมีคำที่ดีกว่านี้ แต่ผมยังคิดคำที่ดีกว่านี้ไม่ออก ซึ่งอาจจะเป็นคำอื่นก็ได้)&lt;&#x2F;p&gt;
&lt;p&gt;จึงเป็นที่มาของบทความนี้ครับ ว่าต้องการสื่อสารออกไปว่า บางครั้งเรามีการระบุ Type ของ Generic แบบ อ้างอิง Source เดียวกัน ซึ่ง TypeScript มีการ Infer Type แบบ Declarative Language ซึ่งเป็น common-problem ในทุกภาษา Declarative อยู่แล้วที่เราจะเจอ เช่นผมเขียน Terraform ผมก็ต้อง Avoid จุดๆ นี้ครบ&lt;&#x2F;p&gt;
&lt;p&gt;แต่ถ้าหากมีคำอื่นเรียกปรากฏการณ์นี้ที่ดีกว่า Circular ก็รบกวนแนะนำหน่อยครับ พอดีผมยืมคำมาจาก Error ของ Terraform ที่สื่อความหมายได้ตรงไปตรงมาดี&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Azure Functions Node.js v4 with TypeScript Weird Part EP.1</title>
		<published>2023-09-20T00:00:00+00:00</published>
		<updated>2023-09-20T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/azure-functions-v4-weird-part-ep1/" type="text/html"/>
		<id>https://thadaw.com/posts/azure-functions-v4-weird-part-ep1/</id>
		<content type="html">&lt;p&gt;Welcome to the first episode of our &quot;Azure Functions Node.js v4 with TypeScript Weird Part&quot; series. In this series, we&#x27;ll dive into some intriguing nuances and challenges you might come across while working with Azure Functions in Node.js version 4, especially when using TypeScript. In this episode, we&#x27;ll explore a type-safety issue that arises when dealing with input and output bindings and provide a practical workaround.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-official-documentation&quot;&gt;The Official Documentation&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-official-documentation&quot; aria-label=&quot;Anchor link for: the-official-documentation&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.npmjs.com&#x2F;package&#x2F;@azure&#x2F;functions&#x2F;v&#x2F;4.0.0-alpha.12&quot;&gt;Azure Functions version 4.0.0-alpha.12&lt;&#x2F;a&gt; introduces a host of exciting features and improvements. However, as you explore this version, you might encounter a seemingly peculiar issue when working with input and output bindings. Let&#x27;s examine the official documentation to get a better understanding.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;input-binding&quot;&gt;Input Binding&lt;a class=&quot;zola-anchor&quot; href=&quot;#input-binding&quot; aria-label=&quot;Anchor link for: input-binding&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;According to the official documentation, you can define an input binding as follows:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;blobInput&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;input&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;storageBlob&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;connection&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;AzureWebJobsStorage&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;demo-input&#x2F;xxx.txt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; To retrieve the value in the handler function, you can use:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;blobInputValue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;extraInputs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;blobInput&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;output-binding&quot;&gt;Output Binding&lt;a class=&quot;zola-anchor&quot; href=&quot;#output-binding&quot; aria-label=&quot;Anchor link for: output-binding&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Similarly, for output bindings:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;blobOutput&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;storageBlob&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;connection&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;AzureWebJobsStorage&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;demo-output&#x2F;xxx-{rand-guid}.txt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; To set the value in the handler function, you can use:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;extraOutputs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;set&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;blobOutput&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;blobInputValue&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;the-type-safety-issue&quot;&gt;The Type-Safety Issue&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-type-safety-issue&quot; aria-label=&quot;Anchor link for: the-type-safety-issue&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;At first glance, everything seems fine. However, there&#x27;s a catch - a lack of type-safety. The issue becomes evident when you attempt to assign a name to your input or output bindings, like so:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;blobInput&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;input&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;storageBlob&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;MyBlobInput&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Error: &amp;#39;name&amp;#39; does not exist in type &amp;#39;StorageBlobInputOptions&amp;#39;.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;connection&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;AzureWebJobsStorage&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;demo-input&#x2F;xxx.txt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;blobOutput&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;storageBlob&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;MyBlobOutput&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Error: &amp;#39;name&amp;#39; does not exist in type &amp;#39;StorageBlobOptions&amp;#39;.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;connection&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;AzureWebJobsStorage&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;demo-output&#x2F;xxx-{rand-guid}.txt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you can see, TypeScript complains that &#x27;name&#x27; does not exist in the type &#x27;StorageBlobInputOptions&#x27; even though the documentation suggests using it. This can be quite frustrating for developers looking to add some meaningful names to their bindings.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-workaround&quot;&gt;The Workaround&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-workaround&quot; aria-label=&quot;Anchor link for: the-workaround&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;But don&#x27;t worry, there&#x27;s a workaround that allows you to use &#x27;name&#x27; and call it later in the handler function while maintaining type-safety. Let&#x27;s see how it&#x27;s done:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;app&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;input&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;InvocationContext&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;HttpRequest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;StorageBlobInputOptions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;StorageBlobOptions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;@azure&#x2F;functions&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;blobInput&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;input&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;storageBlob&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;MyBlobInput&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;connection&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;AzureWebJobsStorage&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;demo-input&#x2F;xxx.txt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;StorageBlobInputOptions&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;blobOutput&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;storageBlob&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;MyBlobOutput&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;connection&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;AzureWebJobsStorage&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;demo-output&#x2F;xxx-{rand-guid}.txt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;StorageBlobOptions&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;app&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;copyBlob&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;authLevel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;anonymous&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;extraInputs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;blobInput&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;extraOutputs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;blobOutput&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;handler&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HttpRequest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;InvocationContext&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Storage queue function processed work item:&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;blobInputValue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;extraInputs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;MyBlobInput&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;extraOutputs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;set&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;MyBlobOutput&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;blobInputValue&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;body&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Hello, &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;blobInputValue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;!&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;By using type assertions (as) to extend the StorageBlobInputOptions and StorageBlobOptions types with the &#x27;name&#x27; property, we can now use &#x27;name&#x27; and maintain type-safety in our code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;in-conclusion&quot;&gt;In Conclusion&lt;a class=&quot;zola-anchor&quot; href=&quot;#in-conclusion&quot; aria-label=&quot;Anchor link for: in-conclusion&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;In this episode of &quot;Azure Functions Node.js v4 with TypeScript Weird Part,&quot; we&#x27;ve explored a type-safety issue related to defining names for input and output bindings. While this issue may appear unusual, we&#x27;ve provided a practical workaround that allows you to use the &#x27;name&#x27; property as intended without compromising TypeScript&#x27;s valuable type-checking features.&lt;&#x2F;p&gt;
&lt;p&gt;As I prepare to submit your Pull Request and engage in discussions with the project&#x27;s author, Keep an eye out for upcoming episodes in this series, where we&#x27;ll continue to investigate and resolve other peculiar aspects of working with Azure Functions in Node.js v4 and TypeScript. Happy coding, fellow geeks!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธีตรวจสอบให้ Zod schemas ตรงกับ Type ที่ประกาศไว้อยู่แล้ว</title>
		<published>2023-09-15T00:00:00+00:00</published>
		<updated>2023-09-15T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/typecheck-schemas-on-existing-types/" type="text/html"/>
		<id>https://thadaw.com/posts/typecheck-schemas-on-existing-types/</id>
		<content type="html">&lt;p&gt;วันนี้เราจะมาพูดถึงวิธีการในการตรวจสอบความเข้ากันได้ระหว่าง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;colinhacks&#x2F;zod&quot;&gt;Zod&lt;&#x2F;a&gt; Schema และ TypeScript อย่างสะดวกและรวดเร็ว ไอเดียดีๆ นี้มาจาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;colinhacks&quot;&gt;@colinhacks&lt;&#x2F;a&gt; ซึ่งเป็นคนสร้าง Zod โดยการใช้ Zod และอยากแบ่งปันให้ทุกคน&lt;&#x2F;p&gt;
&lt;p&gt;โดยปกติแล้ว เราบ่งบอกประเภทของข้อมูลด้วย TypeScript เพื่อให้รู้ว่าข้อมูลที่เราใช้เป็นแบบไหน แต่ถ้าเราใช้ Zod Schema เพื่อทำการตรวจสอบข้อมูล มีวิธีหนึ่งที่จะทำให้เราสามารถตรวจสอบความเข้ากันได้ระหว่าง Zod Schema และ TypeScript ได้อย่างมีประสิทธิภาพ และเรียบง่าย นั่นคือการใช้ฟังก์ชัน &lt;code&gt;schemaForType&lt;&#x2F;code&gt; ตามตัวอย่างด้านล่าง:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;z&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;zod&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Dog&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;neutered&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;boolean&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;schemaForType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TSchema&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TZodSchema&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ZodType&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TSchema&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;arg&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TZodSchema&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;arg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ใช้งานได้ประมาณนี้:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;dog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;schemaForType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Dog&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;object&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; name: z.string(),  &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;neutered&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;boolean&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ❌ Property &amp;#39;name&amp;#39; is missing in type &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; &amp;#39;{ neutered: boolean; }&amp;#39; but required in type &amp;#39;Dog&amp;#39;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;การทำงานของฟังก์ชันซ้อนกันนี้อาจดูแปลก ๆ แต่มันเป็นจำเป็น เพราะมีระดับการใช้ Generic สองระดับ&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;TypeScript ที่ต้องการ &lt;code&gt;TSchema&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Schema ที่สร้างขึ้นอย่างอัตโนมัติ &lt;code&gt;TZodSchema&lt;&#x2F;code&gt; ซึ่งถูก จำกัดโดย &lt;code&gt;extends z.ZodType&amp;lt;TSchema, any, any&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;อย่างไรก็ตาม คุณไม่ต้องกังวลเกี่ยวกับ &lt;code&gt;any&lt;&#x2F;code&gt; ที่เหลือสองตัวนั้น เนื่องจากเรากำลังใช้ &lt;code&gt;TSchema&lt;&#x2F;code&gt; เป็น Type hint โดยตรง นั่นหมายความว่าเราต้องใช้ฟังก์ชันเพิ่มเติมที่ให้เราสามารถตรวจสอบประเภทของ &lt;code&gt;TZodSchema&lt;&#x2F;code&gt; ได้ ซึ่งนี้เป็นเพราะ TypeScript จำเป็นต้องระบุพารามิเตอร์ Generic ทั้งหมดโดยชัดเจนหรือให้มันถูก Infer ทั้งหมด ไม่สามารถเลือกหรือผสมผสานได้ แม้ว่ามีข้อเสนอรองเรื่องนี้อยู่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;microsoft&#x2F;TypeScript&#x2F;issues&#x2F;26242&quot;&gt;microsoft&#x2F;TypeScript#26242&lt;&#x2F;a&gt; ในเดียวนี้&lt;&#x2F;p&gt;
&lt;p&gt;ดังนั้น เราสามารตรวจสอบให้ Zod schemas ตรงกับ Type ที่ประกาศไว้อยู่แล้ว คุณสามารถใช้ฟังก์ชัน &lt;code&gt;schemaForType&lt;&#x2F;code&gt; เพื่อรักษาความ Consistency ในโปรเจคของคุณอีกด้วย! ขอบคุณที่ติดตามบทความนี้ครับและขอให้สนุกกับการเขียนโปรแกรมนะจ๊ะ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ref&quot;&gt;Ref&lt;a class=&quot;zola-anchor&quot; href=&quot;#ref&quot; aria-label=&quot;Anchor link for: ref&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;colinhacks&#x2F;zod&#x2F;issues&#x2F;372#issuecomment-826380330&quot;&gt;colinhacks&#x2F;zod Issuse#372&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ใช้ ChatGPT ช่วยเรียบเรียงด้วย&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธีสร้าง generic function สำหรับเครื่องมือ data validation ที่เป็นหลากหลายได้ใน typescript</title>
		<published>2023-09-12T00:00:00+00:00</published>
		<updated>2023-09-12T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/typescript-generic-data-validation/" type="text/html"/>
		<id>https://thadaw.com/posts/typescript-generic-data-validation/</id>
		<content type="html">&lt;p&gt;วันนี้เราจะมาเรียนรู้วิธีการสร้างฟังก์ชั่นทั่วไปสำหรับเครื่องมือตรวจสอบข้อมูลใน TypeScript กันครับ!&lt;&#x2F;p&gt;
&lt;p&gt;ในรหัสนี้เราได้สร้างฟังก์ชั่นและประเภทข้อมูลที่ชื่อ &lt;code&gt;AcceptedParser&lt;&#x2F;code&gt; ขึ้นมาก่อน ซึ่งสามารถรับข้อมูลชนิด &lt;code&gt;T&lt;&#x2F;code&gt; และมีสองรูปแบบที่ยอมรับคือ:&lt;&#x2F;p&gt;
&lt;p&gt;ฟังก์ชั่นที่รับ &lt;code&gt;input&lt;&#x2F;code&gt; และคืนค่าข้อมูลประเภท &lt;code&gt;T&lt;&#x2F;code&gt; จากข้อมูลที่รับเข้ามา.
อ็อบเจ็กต์ที่มีเมธอด &lt;code&gt;parse&lt;&#x2F;code&gt; ที่รับ &lt;code&gt;input&lt;&#x2F;code&gt; และคืนค่าข้อมูลประเภท T จากข้อมูลที่รับเข้ามา.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ขอบคุณ AcceptedParser จาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;total-typescript&#x2F;untypeable&#x2F;blob&#x2F;main&#x2F;src&#x2F;types.ts&quot;&gt;untypeable&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;AcceptedParser&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-paren z-cover z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;input&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-return z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;parse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;input&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-return z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;หลังจากนั้นเราได้สร้างคลาส &lt;code&gt;Entity&lt;&#x2F;code&gt; ซึ่งใช้สำหรับการจัดการข้อมูลของเรา&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;Entity&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TSchema&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-storage z-type z-ts&quot;&gt;constructor&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;schema&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-optional z-ts&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;AcceptedParser&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TSchema&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;undefined&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;parse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TSchema&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;undefined&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;schema&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;parse&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-expression z-in z-ts&quot;&gt;in&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;schema&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;schema&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;parse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;schema&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;schema&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;data&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TSchema&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;คลาสนี้ยังรับ &lt;code&gt;schema&lt;&#x2F;code&gt; ที่เป็น &lt;code&gt;AcceptedParser&lt;&#x2F;code&gt; ใน constructor ของมันด้วย และมีเมธอด &lt;code&gt;parse&lt;&#x2F;code&gt; ที่รับข้อมูล &lt;code&gt;data&lt;&#x2F;code&gt; และตรวจสอบ &lt;code&gt;schema&lt;&#x2F;code&gt; ว่ามี parse หรือไม่ ถ้ามีเราใช้ &lt;code&gt;parse&lt;&#x2F;code&gt; จาก &lt;code&gt;schema&lt;&#x2F;code&gt; นี้เพื่อแปลงข้อมูล &lt;code&gt;data&lt;&#x2F;code&gt; และคืนค่าออกมา ถ้าไม่มีเราใช้ &lt;code&gt;schema&lt;&#x2F;code&gt; โดยตรงเพื่อแปลงข้อมูล data และคืนค่าออกมา.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;InferEntity&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Entity&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;นอกจากนี้เรายังสร้าง &lt;code&gt;InferEntity&lt;&#x2F;code&gt; ซึ่งเป็นประเภทที่ใช้สำหรับการดึงประเภทข้อมูลจาก &lt;code&gt;Entity&lt;&#x2F;code&gt; โดยอัตโนมัติ แต่ถ้าไม่ใช่ &lt;code&gt;Entity&lt;&#x2F;code&gt; ก็จะคืนค่า never.&lt;&#x2F;p&gt;
&lt;p&gt;ต่อมาเรามาดูตัวอย่างการใช้งาน:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Consumer&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;z&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;zod&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Entity&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;object&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;email&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;email&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;UserEntity&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;InferEntity&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-typeof z-ts&quot;&gt;typeof&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;user&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;parse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;John&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;email&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Type will be&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; const data: {&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;     name: string;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;     email: string;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; } | undefined&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ในตัวอย่างนี้เราสร้าง &lt;code&gt;Entity&lt;&#x2F;code&gt; ของผู้ใช้ (&lt;code&gt;UserEntity&lt;&#x2F;code&gt;) โดยใช้ Zod เป็น &lt;code&gt;schema&lt;&#x2F;code&gt; ที่กำหนดข้อมูลของผู้ใช้ และเราใช้ &lt;code&gt;parse&lt;&#x2F;code&gt; เพื่อแปลงข้อมูลที่เราส่งเข้ามาใน &lt;code&gt;data&lt;&#x2F;code&gt; กับ &lt;code&gt;schema&lt;&#x2F;code&gt; ของเรา ในที่นี้เราจะได้ผลลัพธ์ที่เป็น &lt;code&gt;UserEntity&lt;&#x2F;code&gt; หรือ &lt;code&gt;never&lt;&#x2F;code&gt; ถ้าไม่สามารถแปลงข้อมูลได้.&lt;&#x2F;p&gt;
&lt;p&gt;หรือเราสามารถประกาศแค่ Generic ก็ได้โดยไม่ต้องใช้ Zod&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Entity&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;user&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;parse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;John&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Type will be&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; const data: {&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;     name: string;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; } | undefined&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;หวังว่าบทความนี้จะช่วยให้คุณเข้าใจการสร้างฟังก์ชั่นทั่วไปสำหรับเครื่องมือตรวจสอบข้อมูลใน TypeScript ได้เพิ่มเติมครับ!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;play?noImplicitReturns=false#code&#x2F;PTAEBkEsCMChZKAFgFxQBwM4C4QHNIUkBXaAOgGMB7AW2BSpQEMAbAWhQE90BTTCgE6R0KYMQB2XXk2gsewWVWjAaTSOOCYBFetz5kUmeDwAe6KgJSgpPUAEEKFHiJ4ATAApMBmHgIA8ACoAfKAAvLCgoAA+oAAUseroxCjYoBIA1uJUAO7iAJRhIQF5EdGgAN6lkZHoXj6pCeJJKWnimTn5haABANxVoAC+fbCm5pagFCxMmJigAKKShJyBAMoUSDyqIZWR1OKYKALEFAwCsUmykBSg-BuqAPypDk4uHnW+q+ubTCExEq48ABm6jcBXKA3gNXesVcTGYqQyWVyeVSATWdyYZX+QJBrgq-UggLiREgmDIt2+oAAZFTQAByWreHh00DqaxIUnkr6qMH9SICHgoYgCcTszkU1RkRk+GFwph5PrVQYEomxElkiXy-FK-mC4Wi9VcjGy5gK-oQpUCoUi0Cw5igabddHfRXKiEjMwWKw2UAASXEgN8CxQS0CIVC3VAphQPHErlmwdD6kDAlAAFUQvd06BUuIeAA3XzDBBgADCVH2xBovngkBoYysAC9QICBLR6Y2qK46cM9gc0j5UxG89l5osuLFSo2yEoAFY8E6xHbVcRMaupacHITiPCxPIAGn630gLA35MO6l3eTIx5Ye8PkQGJTNHob1j06cHia4YT9AaD47LDYVBEsQg5BL2Fb9namIRmBvhStCy6ruu9IAFJUEg4h0g+UaqCeqR0jhsBPn0iABB+2QniwoDQDwJYTFBVgwaklSIEqKE8KkW6XmRYBKre3EXjufGDFicY4nmrhAA&quot;&gt;playground&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aanephim&quot;&gt;อ่านเพิ่ม&lt;a class=&quot;zola-anchor&quot; href=&quot;#aanephim&quot; aria-label=&quot;Anchor link for: aanephim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ลองดูตัวอย่างการรับ Data Validation หลายๆ เจ้าดูนะ โดยไม่ผูกติด&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;decs&#x2F;typeschema&quot;&gt;TypeSchema&lt;&#x2F;a&gt; -- Universal adapter for schema validation&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;trpc.io&#x2F;&quot;&gt;tRPC&lt;&#x2F;a&gt;&#x27;s &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;trpc.io&#x2F;docs&#x2F;server&#x2F;validators&quot;&gt;input &amp;amp; output validators&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;total-typescript&#x2F;untypeable&#x2F;blob&#x2F;main&#x2F;src&#x2F;types.ts&quot;&gt;untypeable&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธี Backup Database และเตรียม Migration Script บน SQL Server ด้วย command line</title>
		<published>2023-08-20T00:00:00+00:00</published>
		<updated>2023-08-20T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/backup-database-prepare-migration-script-sql-server-via-command-line/" type="text/html"/>
		<id>https://thadaw.com/posts/backup-database-prepare-migration-script-sql-server-via-command-line/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;หมายเหตุ บทความนี้ Draft ไว้ตั้งแต่วันที่ Sep 20, 2021 ถ้ามีเนื้อหาไหนที่ไม่ได้ Up-to-date ก็สามารถแจ้งได้เลยนะครับ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;สวัสดีครับ! วันนี้เรามีข้อมูลน่าสนใจเกี่ยวกับโปรแกรม &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;sql&#x2F;ssms&#x2F;download-sql-server-management-studio-ssms?view=sql-server-ver15&quot;&gt;SQL Server Management Studio (SSMS)&lt;&#x2F;a&gt; และ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;sql&#x2F;ssdt&#x2F;sql-server-data-tools?view=sql-server-ver16&quot;&gt;SQL Server Data Tools (SSDT)&lt;&#x2F;a&gt; ที่จะมาแนะนำให้คุณรู้จักเพิ่มเติมเกี่ยวกับวิธีการใช้งานเบื้องต้น สำหรับการจัดการฐานข้อมูล SQL Server อย่างสะดวกและง่ายดายโดยไม่ต้องใช้คำสั่ง command line อันซับซ้อนนะครับ!&lt;&#x2F;p&gt;
&lt;p&gt;เริ่มต้นจาก SQL Server Management Studio (SSMS) ซึ่งเป็นโปรแกรมที่ช่วยให้คุณจัดการกับข้อมูลใน SQL Server ได้อย่างสะดวก คุณสามารถดาวน์โหลด SSMS ได้จาก ที่นี่ นะครับ.&lt;&#x2F;p&gt;
&lt;p&gt;นอกจากนี้ยังมี SQL Server Data Tools (SSDT) ที่มาช่วยเพิ่มความสะดวกในการจัดการฐานข้อมูล SQL Server ด้วยครับ โดยคุณสามารถตั้งค่าสภาพแวดล้อมการทำงานของ SSDT ได้ที่ &lt;code&gt;C:\Program Files\Microsoft SQL Server\150\DAC\bin&lt;&#x2F;code&gt; นะครับ.&lt;&#x2F;p&gt;
&lt;p&gt;ต่อไปเรามาดูวิธีการ Export ข้อมูลและ Schema กันครับ คุณสามารถทำเหมือนกับการ Export a Data-tier Application ใน SSMS ได้โดยใช้คำสั่ง PowerShell ซึ่ง Extension ไฟล์ที่ได้จะเป็น &lt;code&gt;.bacpac&lt;&#x2F;code&gt; ดังนี้:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;powershell&quot; class=&quot;language-powershell z-code&quot;&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;sqlpackage &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;Action:Export &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;SourceConnectionString:&lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Data Source=.\SQLEXPRESS; Initial Catalog=TestDB; Integrated Security=True&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;TargetFile:&lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;D:\auto-deployment\database_backup.bacpac&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;หลังจากนั้นถ้าคุณต้องการ Import ข้อมูลนี้เข้าสู่ระบบอื่น ๆ คุณสามารถใช้คำสั่ง PowerShell ต่อไปนี้:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;powershell&quot; class=&quot;language-powershell z-code&quot;&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;sqlpackage &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;Action:Import &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;TargetConnectionString:&lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Data Source=.\SQLEXPRESS; Initial Catalog=Imported_TestDB; Integrated Security=True&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;SourceFile:&lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;D:\auto-deployment\database_backup.bacpac&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;นอกจากนี้ยังมีการดึง Schema อย่างเดียวไม่รวม Data ไปใช้งานด้วยคำสั่ง Extract โดย Extension ไฟล์ที่ได้จะเป็น `.dacpac`` นะครับ:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;powershell&quot; class=&quot;language-powershell z-code&quot;&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;sqlpackage &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;Action:Extract &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;SourceConnectionString:&lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Data Source=.\SQLEXPRESS; Initial Catalog=TestDB; Integrated Security=True&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;TargetFile:&lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;D:\auto-deployment\database_schema.dacpac&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;หากคุณต้องการสร้างรายงาน Diff Report ระหว่าง Schema คุณสามารถใช้คำสั่ง DeployReport ดังนี้ โดย SourceFile ต้องเป็น &lt;code&gt;dacpac&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;powershell&quot; class=&quot;language-powershell z-code&quot;&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;sqlpackage &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;Action:DeployReport &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;OutputPath:&lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;D:\auto-deployment\report.xml&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;OverwriteFiles:True &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;SourceFile:&lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;D:\auto-deployment\TestDatabase\Snapshots\TestDatabase_20210916_17-58-02.dacpac&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;TargetConnectionString:&lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Data Source=.\SQLEXPRESS; Initial Catalog=TestDB; Integrated Security=True&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;และสุดท้าย หากคุณต้องการสร้างสคริปต์สำหรับการเคลื่อนย้ายข้อมูล คุณสามารถใช้คำสั่ง Script ดังนี้:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;powershell&quot; class=&quot;language-powershell z-code&quot;&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;sqlpackage &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;Action:Script &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;OutputPath:&lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;D:\auto-deployment\migration.sql&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;OverwriteFiles:True &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;SourceFile:&lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;D:\auto-deployment\TestDatabase\Snapshots\TestDatabase_20210916_17-58-02.dacpac&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;TargetConnectionString:&lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Data Source=.\SQLEXPRESS; Initial Catalog=TestDB; Integrated Security=True&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;aehlng-aang-ing-aelasueksaaephimetim&quot;&gt;แหล่งอ้างอิง และศึกษาเพิ่มเติม&lt;a class=&quot;zola-anchor&quot; href=&quot;#aehlng-aang-ing-aelasueksaaephimetim&quot; aria-label=&quot;Anchor link for: aehlng-aang-ing-aelasueksaaephimetim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.mssqltips.com&#x2F;sqlservertip&#x2F;4759&#x2F;sql-server-database-schema-synchronization-via-sqlpackageexe-and-powershell&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.mssqltips.com&#x2F;sqlservertip&#x2F;4759&#x2F;sql-server-database-schema-synchronization-via-sqlpackageexe-and-powershell&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;20673516&#x2F;command-line-api-for-schema-compare-in-ssdt-sql-server-database-project&quot;&gt;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;20673516&#x2F;command-line-api-for-schema-compare-in-ssdt-sql-server-database-project&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;How to: Create a New Database Project: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;sql&#x2F;ssdt&#x2F;how-to-create-a-new-database-project?view=sql-server-ver15&quot;&gt;https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;sql&#x2F;ssdt&#x2F;how-to-create-a-new-database-project?view=sql-server-ver15&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธีซ่อนค่า Secrets ใน GitHub Actions</title>
		<published>2023-08-19T00:00:00+00:00</published>
		<updated>2023-08-19T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/how-to-hide-github-action-secrets/" type="text/html"/>
		<id>https://thadaw.com/posts/how-to-hide-github-action-secrets/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;หมายเหตุ บทความนี้ Draft ไว้ตั้งแต่วันที่ Apr 11, 2022 ถ้ามีเนื้อหาไหนที่ไม่ได้ Up-to-date ก็สามารถแจ้งได้เลยนะครับ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ปัญหาหลักที่เราพบคือการอ่านค่า Secrets จากไฟล์ที่เข้ารหัสแบบ SOPS และการซ่อนค่านี้ เรามีวิธีการแก้ไขในตัวอย่างต่อไปนี้ครับ&lt;&#x2F;p&gt;
&lt;p&gt;ในตัวอย่างนี้ เราจะใช้ไฟล์ README.md มาเป็นตัวอย่าง ซึ่งเป็นไฟล์ปกติ แล้วเราจะนำค่าของไฟล์นี้มาซ่อน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yml&quot; class=&quot;language-yml z-code&quot;&gt;&lt;code class=&quot;language-yml&quot; data-lang=&quot;yml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;steps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;actions&#x2F;checkout@v2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Mask Password&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;mark_password&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-block-scalar z-literal z-yaml&quot;&gt;|&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;      secret=`cat &amp;quot;README.md&amp;quot;`
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;      echo &amp;quot;::add-mask::$secret&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;      echo &amp;quot;::set-output name=password::$secret&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;&lt;&#x2F;span&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;echo &amp;quot;${{ steps.mark_password.outputs.password }}&amp;quot;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ผลลัพธ์จากการทำงานข้างบนจะเป็นดังรูปภาพต่อไปนี้:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;how-to-hide-github-action-secrets&#x2F;screenshot.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;เราคิดว่าในขั้นตอนที่ใช้ `add-mask`` น่าจะเป็นวิธีให้ค่าที่เราซ่อนแสดงผลในคอนโซลได้ แบบที่เราไม่เห็นค่าจริงๆ&lt;&#x2F;p&gt;
&lt;p&gt;หวังว่าข้อมูลนี้จะมีประโยชน์และช่วยให้ท่านสามารถแก้ปัญหาที่เจอได้ครับ&lt;&#x2F;p&gt;
&lt;p&gt;อ้างอิง: https:&#x2F;&#x2F;github.com&#x2F;actions&#x2F;runner&#x2F;issues&#x2F;475#issuecomment-1092734499&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธีการตั้งค่า Uptime Kuma บน Azure Virtual Machine</title>
		<published>2023-08-18T00:00:00+00:00</published>
		<updated>2023-08-18T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/uptime-kuma-on-azure-virtual-machine/" type="text/html"/>
		<id>https://thadaw.com/posts/uptime-kuma-on-azure-virtual-machine/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;หมายเหตุ บทความนี้ Draft ไว้ตั้งแต่วันที่ Dec 21, 2022 ถ้ามีเนื้อหาไหนที่ไม่ได้ Up-to-date ก็สามารถแจ้งได้เลยนะครับ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;สวัสดีครับเพื่อนๆ ผู้อ่านทุกท่านที่กำลังมองหาวิธีการตั้งค่า Uptime Kuma บน Azure Virtual Machine ในบทความนี้เราจะมาแนะนำขั้นตอนการทำงานให้รู้เรื่องและเข้าใจง่ายๆ พร้อมกันนะครับ&lt;&#x2F;p&gt;
&lt;p&gt;เมื่อคุณพยายามติดตั้ง Uptime Kuma บน Azure App Service โดยใช้ Azure Files แล้ว
คุณอาจพบข้อผิดพลาดเช่นนี้ &lt;strong&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;louislam&#x2F;uptime-kuma&#x2F;issues&#x2F;1096&quot;&gt;ดูรายละเอียดเพิ่มเติมที่ uptime-kuma#1096&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;vbnetCopy code
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[Error: PRAGMA journal_mode = WAL - SQLITE_BUSY: database is locked]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เมื่อลองใช้งาน Azure App Service กับ Kuma Uptime จะพบว่า Kuma ต้องการ SQLite ในรูปแบบที่เป็น local
เท่าที่อ่านจาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;app-service&#x2F;configure-connect-to-azure-storage?tabs=portal&amp;amp;pivots=container-linux&quot;&gt;Official Doc &quot;Mount Azure Storage as a local share in App Service&quot;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;It isn&#x27;t recommended to use storage mounts for local databases (such as SQLite) or for any other applications and components that rely on file handles and locks.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;พบว่าเค้าไม่แนะนำให้เรา mount volume จำพวก local database เช่น SQLite หรือพวกแอพที่ต้องจัดการเรื่องไฟล์ หรือกลไกการ Lock&lt;&#x2F;p&gt;
&lt;p&gt;ดังนั้น สิ่งที่คุณควรทำคือใช้ Virtual Machine (VM) แทน
ในขั้นตอนถัดไปคือการติดตั้ง Docker บน Azure Virtual Machine
และคุณสามารถเพิ่ม Custom Domain ด้วย DNS A Record และ IP v4 ได้ตามขั้นตอนที่แนะนำไว้ในลิงก์นี้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;virtual-machines&#x2F;custom-domain&quot;&gt;azure&#x2F;virtual-machines&#x2F;custom-domain&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;เพื่อให้การเชื่อมต่อเป็น https คุณสามารถใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;louislam&#x2F;uptime-kuma&#x2F;wiki&#x2F;Reverse-Proxy#https-portal&quot;&gt;Docker-compose และ &lt;strong&gt;&lt;code&gt;https-portal&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt; ได้นะ&lt;&#x2F;p&gt;
&lt;p&gt;ตัวอย่างการตั้งค่า Docker Compose สำหรับ Uptime Kuma และ &lt;strong&gt;&lt;code&gt;https-portal&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; สามารถดูได้ดังนี้ครับ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yml&quot; class=&quot;language-yml z-code&quot;&gt;&lt;code class=&quot;language-yml&quot; data-lang=&quot;yml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;3.3&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;services&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;https-portal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;steveltn&#x2F;https-portal:1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;ports&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;80:80&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;443:443&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;links&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;uptime-kuma&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;restart&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;always&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;environment&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;DOMAINS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;yourdomain.com -&amp;gt; http:&#x2F;&#x2F;uptime-kuma:3001&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;STAGE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;production&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Don&amp;#39;t use production until staging works
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; FORCE_RENEW: &amp;#39;true&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;WEBSOCKET&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;true&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;volumes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;https-portal-data:&#x2F;var&#x2F;lib&#x2F;https-portal&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uptime-kuma&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;louislam&#x2F;uptime-kuma:1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;container_name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;uptime-kuma&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;volumes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;.&#x2F;uptime-kuma:&#x2F;app&#x2F;data&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;ports&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;3001:3001&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;restart&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;always&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;volumes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;https-portal-data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถ้าคุณกำลังมองหาวิธีการตั้งค่า Uptime Kuma บน Azure Virtual Machine คุณสามารถทำตามขั้นตอนที่กล่าวมาได้อย่างง่ายดาย&lt;&#x2F;p&gt;
&lt;p&gt;ป.ล. สำนวนภาษาอาจจะแปลกๆ บ้างนะ เพราะใช้ ChatGPT ช่วยเรียบเรียงให้&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aanephimetim&quot;&gt;อ่านเพิ่มเติม&lt;a class=&quot;zola-anchor&quot; href=&quot;#aanephimetim&quot; aria-label=&quot;Anchor link for: aanephimetim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=q7J050yovuo&quot;&gt;Using Azure File Shares as Container Volume Mounts in App Services&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ถ้าคุณต้องการเพิ่มความสามารถให้เว็บไซต์ของคุณมีความเสถียรและพร้อมใช้งานเสมอ ก็สามารถใช้ Uptime Kuma พร้อมกับ Docker และ Traefik ได้ตามคำแนะนำในลิงก์นี้เลย &lt;strong&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;levelup.gitconnected.com&#x2F;use-docker-uptime-kuma-and-traefik-to-monitor-your-website-593373f9e0c2&quot;&gt;Use Docker, Uptime Kuma, and Traefik To Monitor Your Website&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; สำหรับบริการดีๆ แบบนี้&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธีการ Import Terraform State ใน Terraform Cloud</title>
		<published>2023-08-07T00:00:00+00:00</published>
		<updated>2023-08-07T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/how-to-import-terraform-state-in-terraform-cloud/" type="text/html"/>
		<id>https://thadaw.com/posts/how-to-import-terraform-state-in-terraform-cloud/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;Terraform v1.5.2&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;payhaa&quot;&gt;ปัญหา&lt;a class=&quot;zola-anchor&quot; href=&quot;#payhaa&quot; aria-label=&quot;Anchor link for: payhaa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เวลาเราใช้งาน Terraform Cloud มันจะมีประเด็นอยู่คือ Terraform ไม่ให้เรา Import Resource ใหม่ถ้าเราใช้ Variable ที่เป็น Secret ที่อยู่บน Terraform Cloud&lt;&#x2F;p&gt;
&lt;h2 id=&quot;withiiaekebuue-ngtn&quot;&gt;วิธีแก้เบื้องต้น&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiiaekebuue-ngtn&quot; aria-label=&quot;Anchor link for: withiiaekebuue-ngtn&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;รันคำสั่ง เพื่อดึง State ที่อยู่บน Cloud ลงมาที่ local ก่อน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; state pull &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; terraform.tfstate&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ลบโฟลเดอร์ &lt;code&gt;.terraform&lt;&#x2F;code&gt; เพราะว่าเรามีการเชื่อมต่อกับ Terraform Cloud ไว้แล้ว (หมายถึงเก็บ Terraform State ที่ Terraform Cloud)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;rf&lt;&#x2F;span&gt; .terraform&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ให้ comment ส่วนของ block &lt;code&gt;cloud&lt;&#x2F;code&gt; ไว้ก่อน (Remote State) ยกตัวอย่าง Code ข้างล่างผมใช้ provide &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;registry.terraform.io&#x2F;providers&#x2F;hashicorp&#x2F;azurerm&#x2F;latest&#x2F;docs&quot;&gt;azurerm&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;terraform {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  required_version = &amp;quot;&amp;gt;= 1.5.2&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  required_providers {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    azurerm = {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    source  = &amp;quot;hashicorp&#x2F;azurerm&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    version = &amp;quot;~&amp;gt; 3.58&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  # cloud {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  #   organization = &amp;quot;your-organization&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  #   workspaces {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  #     name = &amp;quot;my-terraform&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  #   }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  # }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;provider &amp;quot;azurerm&amp;quot; {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  features {}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;สั่ง &lt;code&gt;terraform init&lt;&#x2F;code&gt; เพื่อเริ่มต้นติดตั้ง module ใหม่ทั้งหมด พอไม่มี block &lt;code&gt;cloud&lt;&#x2F;code&gt; terraform จะไปใช้งาน local state ซึ่งนั้่นก็คือไฟล์ &lt;code&gt;terraform.tfstate&lt;&#x2F;code&gt; ที่เราดาวน์โหลดลงมาในข้อ 1.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; init&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;สั่ง &lt;code&gt;terraform state list&lt;&#x2F;code&gt; เพื่อดูว่ามี State อยู่ที่ Local จริงๆ นะ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; state list&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;จากนั้นให้เริ่ม import resource ตามที่เราต้องการ เช่น ผมจะ import resource ที่ชื่อ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;registry.terraform.io&#x2F;providers&#x2F;hashicorp&#x2F;azurerm&#x2F;latest&#x2F;docs&#x2F;resources&#x2F;linux_web_app#import&quot;&gt;azurerm_linux_web_app&lt;&#x2F;a&gt; ก็สามารถใช้ Syntax import ได้ตามปกติ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; import azurerm_linux_web_app.example &#x2F;subscriptions&#x2F;12345678-1234-9876-4563-123456789012&#x2F;resourceGroups&#x2F;resGroup1&#x2F;providers&#x2F;Microsoft.Web&#x2F;sites&#x2F;site1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;จากนั้นสั่ง &lt;code&gt;terraform state list&lt;&#x2F;code&gt; เพื่อดูว่าที่ import เข้ามาอยู่ใน State แล้วหรือยัง&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; state list&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ให้เอา comment ออกในส่วนของ &lt;code&gt;cloud&lt;&#x2F;code&gt; (Remote State)&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;terraform {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  required_version = &amp;quot;&amp;gt;= 1.5.2&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  required_providers {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    azurerm = {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    source  = &amp;quot;hashicorp&#x2F;azurerm&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    version = &amp;quot;~&amp;gt; 3.58&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  cloud {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    organization = &amp;quot;your-organization&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    workspaces {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;      name = &amp;quot;my-terraform&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;provider &amp;quot;azurerm&amp;quot; {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  features {}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ลบโฟลเดอร์ &lt;code&gt;.terraform&lt;&#x2F;code&gt; เพราะว่าเรามีการเชื่อมต่อใช้ Terraform State อยู่ใน Local ไว้อยู่&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;rf&lt;&#x2F;span&gt; .terraform&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;สั่ง &lt;code&gt;terraform init&lt;&#x2F;code&gt; เพื่อเริ่มต้นติดตั้ง module ใหม่ทั้งหมด พอมี block &lt;code&gt;cloud&lt;&#x2F;code&gt; (Remote State) มันก็จะต่อไปที่ Terraform Cloud อีกครั้ง&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; init&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ซึ่งในขั้นตอนนี้ Terraform จะข้อความมายาวๆ เพื่อถามว่าจะให้ Terraform State บน Local ไปทับ State บน Cloud มั้ย (แนะนำให้ Backup local state ไว้ก่อนทุกครั้ง) จากนั้นให้กด Yes เพื่อเริ่มทำงาน&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Ref: https:&#x2F;&#x2F;github.com&#x2F;hashicorp&#x2F;terraform&#x2F;issues&#x2F;26494&lt;&#x2F;p&gt;
&lt;p&gt;แอบเหนื่อยนิดนึง แต่ก็แก้ปัญหาได้นะ ใครมี Solution ดีๆ มา share กันได้นะ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Write Recursive Type with typeof operator in TypeScript</title>
		<published>2023-02-19T00:00:00+00:00</published>
		<updated>2023-02-19T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/recursive-type-with-typeof-operator/" type="text/html"/>
		<id>https://thadaw.com/posts/recursive-type-with-typeof-operator/</id>
		<content type="html">&lt;h2 id=&quot;i-ve-got-a-problem-i-ve-ask-chatgpt&quot;&gt;I&#x27;ve got a problem, I&#x27;ve ask ChatGPT&lt;a class=&quot;zola-anchor&quot; href=&quot;#i-ve-got-a-problem-i-ve-ask-chatgpt&quot; aria-label=&quot;Anchor link for: i-ve-got-a-problem-i-ve-ask-chatgpt&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;In typescript&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;GetAnyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;readonly&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Tail&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;GetAnyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Tail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;const&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;GetAnyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-typeof z-ts&quot;&gt;typeof&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Result is []&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Why the &lt;code&gt;Result&lt;&#x2F;code&gt; type is &lt;code&gt;[]&lt;&#x2F;code&gt;, i expect &lt;code&gt;[any, any, any]&lt;&#x2F;code&gt;, When I pass:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Result2&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;GetAnyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;the &lt;code&gt;Result2&lt;&#x2F;code&gt; is correct type that is &lt;code&gt;[any, any, any]&lt;&#x2F;code&gt;,&lt;&#x2F;p&gt;
&lt;h2 id=&quot;chatgpt-solution&quot;&gt;ChatGPT Solution&lt;a class=&quot;zola-anchor&quot; href=&quot;#chatgpt-solution&quot; aria-label=&quot;Anchor link for: chatgpt-solution&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;I apologize for the confusion. The issue is that the typeof operator in TypeScript behaves differently for array literals and readonly array literals.&lt;&#x2F;p&gt;
&lt;p&gt;When you define a as [1, 2, 3] as const, it creates a readonly array literal. However, when you use typeof a, the resulting type is readonly [1, 2, 3], which is not considered to be a tuple type by the TypeScript compiler.&lt;&#x2F;p&gt;
&lt;p&gt;To make your original implementation work with readonly array literals, you can add an additional conditional type to handle the case where the input is a readonly array:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;GetAnyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;readonly&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;readonly&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Tail&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;GetAnyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Tail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Tail&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;GetAnyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Tail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;const&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;GetAnyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-typeof z-ts&quot;&gt;typeof&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; [1, 2, 3]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this updated implementation, we use two conditional types to handle both regular arrays and readonly arrays. The first conditional type checks if the input is a readonly tuple type, and the second conditional type checks if the input is a regular tuple type.&lt;&#x2F;p&gt;
&lt;p&gt;I hope this helps!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;recursive-type-with-typeof-operator&#x2F;chatgpt-solution.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Nammatham Note 2: Convert array of keys and array of values to object</title>
		<published>2023-01-25T00:00:00+00:00</published>
		<updated>2023-01-25T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/nammatham-note-2-convert-array-of-keys-and-array-of-values-to-object/" type="text/html"/>
		<id>https://thadaw.com/posts/nammatham-note-2-convert-array-of-keys-and-array-of-values-to-object/</id>
		<content type="html">&lt;p&gt;This orignial question is from &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;67021405&#x2F;ts-types-convert-arrays-of-keys-and-array-of-values-to-object&quot;&gt;Stackoverflow&lt;&#x2F;a&gt;. The &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;catchts.com&#x2F;tuples#zip&quot;&gt;full description&lt;&#x2F;a&gt; how to construct this type utility (from catchts.com)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;A&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cat&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dog&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;B&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;red&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;yellow&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Expected&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;cat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;red&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;dog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;yellow&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The original solution&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Length&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;length&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;L&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;L&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;CompareLength&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;X&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Y&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Length&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;X&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Length&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;true&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * Let&amp;#39;s operate on primitives
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Keys&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;symbol&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;AllowedKeys&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;readonly&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Mapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * Recursive iteration through two arrays
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Zip&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;CompareLength&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadT1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadU1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Mapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadT1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadU1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadT2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TailT2&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadU2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TailU2&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Zip&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;AllowedKeys&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TailT2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;AllowedKeys&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TailU2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Mapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadT2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadU2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * Apply Zip only if arrays length is equal, otherwise return never
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Zipper&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;CompareLength&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;true&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Zip&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;A&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cat&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dog&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;B&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;red&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;yellow&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Zipper&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;A&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;cat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;red&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;dog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;yellow&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ok&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;play?#code&#x2F;C4TwDgpgBAMhB2BzYALAPAFShAHsBAJgM5QBKEAhgQPbwA2IAggE7MUhoXwgB8PUAXihZc+eMSgBvKHQTIUALigBLeADMIzWFAC+AWABQUKAH5Yh40vgQAbpoDchw6EhQAwtQC2YCswhwkVDQLKAANbDxCEnIqWgYWNg4uXgAaEIBNCLEJGJp6JlZ2Tm4eEP4hAPk0UP5RKNg5IPT+M2BmAFdoJTUKOiIIRwNDAHoAKlGLUYbgAHISakg2fChaKDBmZU9lYGU7Iknh53BoAGkIEBIhIjbVRCgAHyh4ds8AI00HqCIQN+o6QZc0EYdDo1AA7hACGcLphysIsvU-LF8lBoUQANoAXVM8KstgcTgMgKgAFkKGBFpgUlAAKpwkSRcQkNE4mkIpmo84kMzkADG1GYBCptP4eLsWjFBKGBjGEyMUz57WYRF20G2mgoO1WqGY1HaiBQUGAYOoUF8iX28sOROOUAAWsowMEDAzstFKHl4oUOGieGkjGy6hzcnECok0L7-WQIER2nRgOychB+YK0NcNkhqck4ZIdOUQh5vL5-I10BhqXTEyQ2p0QmZXfUsXXo7H41AFCEGxz0aoNFoABIejAARkxzcDjIkPfUH0HVBpo+b5FbCYAZKTyZS5wQR9TtwvRU98RLO1WoNO+1BtxgAEzUgB0j97HwwFGUdFvY6MrLPF9nHppO8oEfe9ny0V930Ar9jDMB0nWBUEIShLlMDfD8bz9KAEPBSE0VQyCMOpZc4zXDcKU0NBryA-cMNKb9JWYEIGKYo9xUGEZxkmLCKQYe1HRWFFlDUM1vRIWRAkNZQSAgABHdpempahUE0MEpOgPxgCVeBWM0A4jlcODKS7JNkS9cNI1pM8Q3yBIil9fNv0LHw-EqIJyxFM8a2gWDHWFSsGPYm1XEYQRzwAIl5TUwupMKaEQMLMQBW0ACFQvRMK-AIaKoDCkAIBBcEEqS1xiLbIRDIoxhqWSnhAv5eBrigAAvR0lFKhMhEkEJIuAJQMshaKQjivq8oKsEwsMHQoGGYYVgAayAA&quot;&gt;playground&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I want the Type support value any type, not only &lt;code&gt;string | number | symbol&lt;&#x2F;code&gt; as already defined in:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Keys&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;symbol&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;AllowedKeys&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;readonly&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;my-solution&quot;&gt;My Solution&lt;a class=&quot;zola-anchor&quot; href=&quot;#my-solution&quot; aria-label=&quot;Anchor link for: my-solution&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;play?#code&#x2F;C4TwDgpgBAMhB2BzYALAPAFShAHsBAJgM5QBKEAhgQPbwA2IAggE7MUhoXwgB8PUAXihZc+eMSgBvKHQTIUALigBLeADMIzWFAC+UAPzal8CADdNAbgCwAKFCQoAYWoBbMBWYQ4SVGgAa2HiEJORUtAwsbBxcvAA0UACagWISoTT0TKzsnNx8grByvn78osEFPugJPLZQBlDAzACuEDVQSmoUdEQQ1ja2APQAVIM1gwXAAOQk1JBs+FC0UGDMyi7KwMrmRKP9tvbQANIQICRCRA2qiFAAPlDwjS4ARpo3UEQgT9R0vftQALIUMCzTDxACq-CEIiC4hIRxOdTIEAAxtRmAQQVBwbVjGZLLY9uBoIw6HRqAB3CAEOFETAQ4TJMqeMIZKDUgDaAF06lgceZmL0BsNRoikY1mERNtB1poKBtFqhmNRGogUPUydQoB4otsbFBBrs7ISoAAtZRgNCtKEpEKUdIRLIcak8WKtUEMmGI5n2qI5OKtchERp0YDu1LI1Ho84rJDxGJ0yQ6Wx05xuDxeQroDBgkrQiQNZqtQxWsqc1q1QwBoPAMttemlD1s1QaLQACVtGAAjBya4Y3fWJI31C821RQV2a+XEYHg1AAGT-QHAkcETvxZdj6q62rb3maGtKYsNpvD9sAJniADor8etBgKMo6BhT92t5O+7mSIPm1B1+eoFeLxvYR7zoUFnwnOpTXNYlSQpKljhpO8HyfZ1gIfMD4krGd5wBIFNDQZcnzXW0wL4CDd2Yfc7lxSitwogUbCGEZdTGRggQYE0zQWFllDUTUHRIWQKhUEgIAAR0aTp4moVBNDJZRuigTxgDFeBqL5HYCQcKDgUPMMvUyH0nTBUMbQMyJsjjZNXHcTxvHkDEsX7Eh8xaLdDCgxzN2xdS8T6GwkToCgiBtAgpETAKgpCxIIBJclwvxQ0HEYfI2QAIiRWU0viNKaEQNKOR+I0ACFUvIAh4gSWLYMKrToCwkMhB0-DGHiYqeAYlF4HOKAAC8zSUBr8kkVpMuAQbKRdLc8qUKq4rJWw9H6foFgAayAA&quot;&gt;Playground&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To modify the original code, I&#x27;ve revise&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Keys&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;symbol&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Mapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;โดยตัว &lt;code&gt;Mapper&lt;&#x2F;code&gt; ต้องการ value ของที่จะมา Map (&lt;code&gt;U&lt;&#x2F;code&gt;) เป็น &lt;code&gt;Keys&lt;&#x2F;code&gt; เท่านั้น ซึ่งก็คือ &lt;code&gt;string | number | symbol&lt;&#x2F;code&gt; อย่างใดอย่างหนึ่ง
ซึ่งผมต้องการให้ &lt;code&gt;Mapper&lt;&#x2F;code&gt; รับ value ที่เป็นอะไรก็ได้&lt;&#x2F;p&gt;
&lt;p&gt;ดังนั้นจึงเหลือแค่เช็คว่า Key ที่รับเข้ามาเป็น Valid key หรือไม่ ซึ่งก็คือ  &lt;code&gt;string | number | symbol&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Mapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จุดที่ 2 ที่แก้ไขก็คือ การนิยาย type &lt;code&gt;Zip&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Keys&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;symbol&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Zip&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;โดยที่ Type รับ parameter 2 ตัวที่เป็น Readonly Array ที่เป็น &lt;code&gt;Key&lt;&#x2F;code&gt; ทั้ง key และ value เลยจึงทำให้ในการใช้งาน &lt;code&gt;Zip&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;                    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; v--- 2nd parameter needs to be `string | number | symbol`&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-node z-ts&quot;&gt;Zip&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cat&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dog&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;red&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;yellow&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จึงแก้ไขให้รับ &lt;code&gt;any&lt;&#x2F;code&gt; type แทน&lt;&#x2F;p&gt;
&lt;h2 id=&quot;final-solution&quot;&gt;Final Solution&lt;a class=&quot;zola-anchor&quot; href=&quot;#final-solution&quot; aria-label=&quot;Anchor link for: final-solution&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Length&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;length&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;L&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;L&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;CompareLength&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;X&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Y&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Length&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;X&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Length&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * Let&amp;#39;s operate on primitives
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Keys&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;symbol&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Mapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt;  &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;AllowedKeys&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;readonly&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * Recursive iteration through two arrays
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Zip&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;  &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;CompareLength&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Result&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadT1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadU1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Mapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadT1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadU1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadT2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TailT2&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadU2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TailU2&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Zip&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;AllowedKeys&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TailT2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;TailU2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Mapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadT2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HeadU2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * Apply Zip only if arrays length is equal, otherwise return never
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Zipper&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ReadonlyArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;CompareLength&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Zip&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;Red&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;Yellow&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;A&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cat&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dog&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;B&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Red&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Yellow&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Zipper&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;A&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Result&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;cat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Red&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;dog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Yellow&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ok&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Nammatham Note 3: Extract Type from Object Key to Mapped Object</title>
		<published>2023-01-25T00:00:00+00:00</published>
		<updated>2023-01-25T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/nammatham-note-3-extract-type-from-object-key-to-object/" type="text/html"/>
		<id>https://thadaw.com/posts/nammatham-note-3-extract-type-from-object-key-to-object/</id>
		<content type="html">&lt;p&gt;สวัสดีคับ ผมหวังว่าผู้อ่านน่าจะคุ้นเคย Azure Function TypeScript มาพอสมควรแล้ว ถ้ายังไม่คุ้นก็เดี๋ยวจะได้เริ่มคุ้นเลยนะ
เย้&lt;&#x2F;p&gt;
&lt;p&gt;จาก Issuse #24 (https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;nammatham&#x2F;issues&#x2F;24)&lt;&#x2F;p&gt;
&lt;p&gt;(Refer to &lt;code&gt;@azure&#x2F;functions@3.5.x&lt;&#x2F;code&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;Context.bindings&lt;&#x2F;code&gt; is type &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Azure&#x2F;azure-functions-nodejs-library&#x2F;blob&#x2F;v3.x&#x2F;types&#x2F;Context.d.ts#L76-L79&quot;&gt;ContextBindings&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This will accept &lt;code&gt;string&lt;&#x2F;code&gt; from &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Azure&#x2F;azure-functions-nodejs-library&#x2F;blob&#x2F;v3.x&#x2F;types&#x2F;Context.d.ts#L21-L24&quot;&gt;the source&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Input and trigger binding data, as defined in function.json. Properties on this object are dynamically generated and named based off of the &quot;name&quot; property in function.json.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;here is the definition of &lt;code&gt;Context Binding&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * Context bindings object. Provided to your function binding data, as defined in function.json.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-interface z-ts&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-ts&quot;&gt;ContextBindings&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-indexer z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;expected-behavior&quot;&gt;Expected Behavior&lt;a class=&quot;zola-anchor&quot; href=&quot;#expected-behavior&quot; aria-label=&quot;Anchor link for: expected-behavior&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;If we binding function with name &lt;code&gt;response&lt;&#x2F;code&gt; in &lt;code&gt;function.json&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json z-code&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;bindings&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;    &lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;type&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;http&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;direction&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;out&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;response&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The type should allow only &lt;code&gt;Context.bindings.response&lt;&#x2F;code&gt; type, not any &lt;code&gt;string&lt;&#x2F;code&gt; type.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution&quot; aria-label=&quot;Anchor link for: solution&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;AuthorizationLevel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;BaseController&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;controller&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;functionName&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;nammatham&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;ContextBindings&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;HttpRequest&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;@azure&#x2F;functions&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; import { BindingTypeEnum } from &amp;#39;inversify&amp;#39;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;UnionToIntersection&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;type-fest&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;os&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; https:&#x2F;&#x2F;catchts.com&#x2F;union-array&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Converts union to overloaded function&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;UnionToOvlds&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;UnionToIntersection&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-return z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;void&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;PopUnion&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;UnionToOvlds&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;U&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-function z-return z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;void&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;A&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;IsUnion&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;UnionToIntersection&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;false&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Finally me)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;UnionToArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;A&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;IsUnion&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;UnionToArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Exclude&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;PopUnion&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;PopUnion&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;A&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;A&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; https:&#x2F;&#x2F;catchts.com&#x2F;union-array&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-interface z-ts&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-ts&quot;&gt;BaseFunctionBinding&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;N&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;direction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;in&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;out&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;N&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-interface z-ts&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-ts&quot;&gt;HttpTriggerResponseBinding&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-ts&quot;&gt;BaseFunctionBinding&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;http&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;http&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;direction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;out&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-interface z-ts&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-ts&quot;&gt;HttpTriggerRequestBinding&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-ts&quot;&gt;BaseFunctionBinding&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;httpTrigger&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;httpTrigger&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;direction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;in&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;route&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-optional z-ts&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; * Custom Function Binding can assign any type value
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-block z-documentation z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-interface z-ts&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-ts&quot;&gt;CustomFunctionBinding&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-ts&quot;&gt;BaseFunctionBinding&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;DefinedFunctionBinding&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HttpTriggerRequestBinding&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HttpTriggerResponseBinding&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;bindings&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;req&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;httpTrigger&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;direction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;in&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;route&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&#x2F;home&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HttpTriggerRequestBinding&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;req&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;res&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;direction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;out&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;http&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HttpTriggerResponseBinding&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;res&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;const&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;BindingType&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-expression z-typeof z-ts&quot;&gt;typeof&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;bindings&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;BindingTypeName&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;UnionToArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;BindingType&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;BindingTypeArray&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;UnionToArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;BindingType&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;type&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;AllBindings&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;DefinedFunctionBinding&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;type&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; type AllBindings = &amp;quot;http&amp;quot; | &amp;quot;httpTrigger&amp;quot;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;GetBindingObjectFromType&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;AllBindings&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;httpTrigger&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HttpRequest&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;GetBindingObjectArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;AllBindings&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-infer z-ts&quot;&gt;infer&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Tail&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Head&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;AllBindings&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Tail&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;AllBindings&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;GetBindingObjectFromType&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Head&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rest z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;GetBindingObjectArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Tail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;BindingObjectArray&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;GetBindingObjectArray&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;BindingTypeArray&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; https:&#x2F;&#x2F;catchts.com&#x2F;tuples&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;BindingTypeMapping&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Zipper&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;BindingTypeName&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;BindingObjectArray&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;MyContextBindings&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ContextBindings&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;BindingTypeMapping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;myContextBindings&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;MyContextBindings&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Mock type&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;req&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HttpRequest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;res&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;myContextBindings&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-decorator z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-decorator z-ts&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;controller&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;MyHttpController&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-ts&quot;&gt;BaseController&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-decorator z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-decorator z-ts&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;functionName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;MyHttp&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-spread z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;bindings&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;getName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;HttpRequest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;void&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Context Log&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;bindings&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; this.res.send(`hello get user with ${name}`);&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;res&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;[MyHttp] hello get user with &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;}&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;read-more-ccha&quot;&gt;Read More จ๊ะ&lt;a class=&quot;zola-anchor&quot; href=&quot;#read-more-ccha&quot; aria-label=&quot;Anchor link for: read-more-ccha&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;How to make a map object type from a union type in TypeScript? !!! https:&#x2F;&#x2F;melvingeorge.me&#x2F;blog&#x2F;make-map-object-type-from-union-types-typescript&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;catchts.com&#x2F;union-array&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;65375625&#x2F;typescript-convert-union-of-similar-objects-to-object-type&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;60862509&#x2F;typescript-types-from-array-to-object
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;UnionToIntersection&lt;&#x2F;code&gt; from &lt;code&gt;type-fest&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ลดขนาด Docker Image ของ NestJS&#x2F;Prisma กับ Nx Monorepo ประมาณ 97% ด้วย esbuild Bundle</title>
		<published>2022-12-22T00:00:00+00:00</published>
		<updated>2022-12-22T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/reduce-nestjs-docker-image-size-with-esbuild-bundle/" type="text/html"/>
		<id>https://thadaw.com/posts/reduce-nestjs-docker-image-size-with-esbuild-bundle/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;Update วันที่ 24 Dec 2022:
เพิ่ม Step ที่ 5 ใช้ Alpine เป็น base image และลบ Prisma ไฟล์บางอย่างที่ไม่ได้ใช้งานออก&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;เจ็บปวดกันมาเท่าไหร่กับ ขนาดของ project nodejs ที่ใหญ่มโหฬาร วันนี้ผมจะมาแชร์ประสบการณ์ Workaround ของผมว่าจะลด 80% ได้ยังไง ด้วย esbuild Bundle&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Before&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;REPOSITORY            TAG           IMAGE ID       CREATED       SIZE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote-state-api      debian        f42e4b8e75cb   4 days ago    2.64GB
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;After&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;REPOSITORY            TAG            IMAGE ID       CREATED           SIZE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote-state-api      alpine-unused  12b08b0bfc1f   8 seconds ago     77.8MB
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;โดยสรุปลดจาก 2.64 GB เหลือ 77.8 MB โดยลดไปประมาณ 97%&lt;&#x2F;p&gt;
&lt;h2 id=&quot;stack-thiiaich&quot;&gt;Stack ที่ใช้&lt;a class=&quot;zola-anchor&quot; href=&quot;#stack-thiiaich&quot; aria-label=&quot;Anchor link for: stack-thiiaich&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.prisma.io&#x2F;&quot;&gt;Prisma&lt;&#x2F;a&gt; 4.8.0&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nestjs.com&#x2F;&quot;&gt;Nestjs&lt;&#x2F;a&gt; 9.0.0&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nx.dev&#x2F;&quot;&gt;Nx&lt;&#x2F;a&gt; (Monorepo Tools) 15.3.3&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ถ้าเราเริ่มต้นใช้งาน Nestjs แล้วเริ่มต้นติดตั้ง node_modules ขนาดของ&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;du -sh .&#x2F;node_modules
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;495M   .&#x2F;node_modules
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แล้วถ้าเราใช้ Nx เพื่อกำหนดโครงสร้าง Monorepo ใน repo ของเรามันจะทำให้ใน node_modules ของเราใหญ่ขึ้นมากๆ โดยไม่จำเป็น
ซึ่ง Nx จะมี mode ให้ใช้หลักๆ อยู่ 2 แบบ คือ&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nx.dev&#x2F;getting-started&#x2F;package-based-repo-tutorial&quot;&gt;Package-Based Repos&lt;&#x2F;a&gt; อันนี้จะเป็นแนวเวลาเราใช้งาน monorepo ทั่วๆ ไป โดยที่แต่ละ project จะมี &lt;code&gt;package.json&lt;&#x2F;code&gt; แยกกันเลย จึงทำให้เราสามารถจัดการแต่ละ project แยกกันง่าย และเวลา deploy package แต่ละ Project จะไม่ปนกัน&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;แต่ข้อเสียคือ การ config ให้ tsconfig, eslint, jest ให้มีการใช้งานร่วมกันระหว่างโปรเจ็คได้ ค่อนข้างใช้เวลาเยอะ และ เราไม่สามารถใช้ความสามารถ Generator ของ Nx ได้ ที่สามารถเสก Template TypeScript Project ง่ายๆ&lt;&#x2F;li&gt;
&lt;li&gt;ตัวอย่าง Monorepo ที่ลักษณะคล้ายๆ กันก็คือจะมี &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;yarnpkg.com&#x2F;features&#x2F;workspaces&quot;&gt;Yarn Workspace&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pnpm.io&#x2F;workspaces&quot;&gt;pnpm Workspace&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lerna&#x2F;lerna&quot;&gt;Lerna&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;turbo.build&#x2F;repo&quot;&gt;turborepo&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nx.dev&#x2F;getting-started&#x2F;integrated-repo-tutorial&quot;&gt;Integrated Repos&lt;&#x2F;a&gt; อันนี้จะเป็นลักษณะพิเศษที่จะมีเฉพาะ Nx อย่างที่บอกไปแล้วว่าข้อดีคือ สามารถใช้ความสามารถ Generator ของ Nx ได้ ที่สามารถเสก Template TypeScript Project ง่ายๆ พร้อม config ที่เราใช้งานโดยทั่วไปคือ tsconfig, eslint และ jest&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;แต่ข้อเสียคือ Learning Curve สูงกว่าแบบแรกแน่นอน แต่อย่าลืมว่า การ config ให้ tsconfig, eslint, jest ให้มีการใช้งานร่วมกันระหว่างโปรเจ็คได้ ก็ใช้เวลาเยอะเช่นกัน&lt;&#x2F;li&gt;
&lt;li&gt;อีกข้อดีและข้อเสีย ก็คือการที่มี package.json ที่เดียวในตำแหน่ง root ของ repo เท่านั้น ซึ่งข้อดีก็คือทำให้เราจัดการ package version ไม่ซ้ำซ้อนกัน เช่น Library ที่ใช้งานร่วมกันก็ควรมี dependencies ที่มี version เดียวกัน ดังนั้นการเปลี่ยน version ทุก project จึงเป็นเรื่องไม่ค่อยอยากทำ ส่วนข้อเสียก็คือ เวลาเราจะ deploy หรือ publish บาง project ขนาดของ node_modules จะอ้วนมากๆ&lt;&#x2F;li&gt;
&lt;li&gt;ตัวอย่าง Template ที่ Nx มีให้ใช้ก็เยอะมากๆ หลักๆ คือ React, Angular, Vue, Nestjs และพวก Library Project ต่างๆ ดู plugin ทั้งหมดได้ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nx.dev&#x2F;packages&quot;&gt;Nx Packages&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;cchaakmiimthiiekhaach-baechw-kanain-node-modules&quot;&gt;จากมีมที่เค้าชอบแซวๆ กันใน node_modules&lt;a class=&quot;zola-anchor&quot; href=&quot;#cchaakmiimthiiekhaach-baechw-kanain-node-modules&quot; aria-label=&quot;Anchor link for: cchaakmiimthiiekhaach-baechw-kanain-node-modules&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ใน Project นี้เราจะจึง Stack ที่มีแต่ทำให้ node_modules บวมๆ ขึ้นมากๆ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;reduce-nestjs-docker-image-size-with-esbuild-bundle&#x2F;node-modules-too-big.png&quot; alt=&quot;Ref: https:&#x2F;&#x2F;tsh.io&#x2F;blog&#x2F;reduce-node-modules-for-better-performance&#x2F;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;t&quot;&gt;ต่อๆ&lt;a class=&quot;zola-anchor&quot; href=&quot;#t&quot; aria-label=&quot;Anchor link for: t&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ดังนั้นผมจึงเลือก Integrated Repos ของ Nx มาใช้ในงานนี้ อย่างที่บอกไปว่า Nx แบบ Integrated Repos นั้น ทำให้มี node_modules บางตัวที่ไม่ได้ใช้งาน การที่เราจะ Deploy หรือ Publish ทำให้ขนาดของแอพใหญ่ขึ้นมากๆ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nrwl&#x2F;nx&#x2F;issues&#x2F;1777&quot;&gt;nrwl&#x2F;nx Issues#177&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;step-1-first-docker-image&quot;&gt;Step 1: First Docker Image&lt;a class=&quot;zola-anchor&quot; href=&quot;#step-1-first-docker-image&quot; aria-label=&quot;Anchor link for: step-1-first-docker-image&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จากที่แสดงข้างบนบทความจะเห็นได้ว่าแอพตัวนี้มีขนาด 2.64GB&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;REPOSITORY            TAG           IMAGE ID       CREATED       SIZE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote-state-api      debian        f42e4b8e75cb   4 days ago    2.64GB
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;โดยเรามีการใช้งาน image &lt;code&gt;node:18&lt;&#x2F;code&gt; แค่ Image เปล่าๆ ก็ขนาด 942 MB เข้าไปแล้ว&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;REPOSITORY            TAG       IMAGE ID       CREATED        SIZE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;node                  18        c6b41dff69c8   20 hours ago   942MB
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แสดงว่าแอพของเราไม่รวม base image จะมีขนาดประมาณ 1.72 GB โอ้วแม่เจ้า อะไรจะใหญ่ขนาดนี้&lt;&#x2F;p&gt;
&lt;h3 id=&quot;taw-yaang-dockerfile-thiiaichain-step-nii&quot;&gt;ตัวอย่าง Dockerfile ที่ใช้ใน Step นี้&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaang-dockerfile-thiiaichain-step-nii&quot; aria-label=&quot;Anchor link for: taw-yaang-dockerfile-thiiaichain-step-nii&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;dockerfile&quot; class=&quot;language-dockerfile z-code&quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; node:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;18&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;As&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;development&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;curl -f https:&#x2F;&#x2F;get.pnpm.io&#x2F;v6.16.js | node - add --global pnpm
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; .&#x2F;dist&#x2F;apps&#x2F;remote-state-server .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; apps&#x2F;remote-state-server&#x2F;prisma .&#x2F;prisma&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; package.json pnpm-lock.yaml .&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;PORT=3333
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;EXPOSE &lt;&#x2F;span&gt;${PORT}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpm fetch --prod
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpm install
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpx prisma generate
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; We don&amp;#39;t have the existing sqlite file
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; So, we will create a fresh sqlite every time when build
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; This migration should be run every time when build
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpx prisma migrate deploy
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-dockerfile&quot;&gt;CMD &lt;&#x2F;span&gt;node .&#x2F;main.js
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ซึ่งใน Dockerfile นี้ผมไม่ได้ Build ใน Docker แต่จะ Build ที่เครื่อง Host ให้เสร็จแล้ว copy เข้ามาตอน build แทน ซึ่งก่อน Build ผมจะรัน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; run remote-state-server:build:production&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ป.ล. &lt;code&gt;remote-state-server:build:production&lt;&#x2F;code&gt; ตัวนี้เป็น executor default ของ template Nestjs โดยจะใช้ executor ที่ชื่อว่า &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nx.dev&#x2F;packages&#x2F;webpack&#x2F;executors&#x2F;webpack&quot;&gt;@nrwl&#x2F;webpack:webpack&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;โดยใน Docker Image ผมจะมีการรัน &lt;code&gt;prisma generate&lt;&#x2F;code&gt; เพื่อรัน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.prisma.io&#x2F;docs&#x2F;concepts&#x2F;components&#x2F;prisma-client&#x2F;working-with-prismaclient&#x2F;generating-prisma-client&quot;&gt;script postinstall ของ Prisma เอง&lt;&#x2F;a&gt; และรัน &lt;code&gt;prisma migrate deploy&lt;&#x2F;code&gt; ทุกครั้งที่ Build เพราะผมใช้ Sqlite ใน image นี้ด้วย และต้องการให้มัน clean ทุกครั้งที่ build ส่วนใครที่ไม่ใช้งานสามารถลบออกไปได้คับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;step-2-swasdii-alpine-image&quot;&gt;Step 2: สวัสดี Alpine Image&lt;a class=&quot;zola-anchor&quot; href=&quot;#step-2-swasdii-alpine-image&quot; aria-label=&quot;Anchor link for: step-2-swasdii-alpine-image&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ใน Step นี้ผมจะใช้ Docker multi-stage และติดตั้งเฉพาะ dependencies สำหรับ Production อย่างเดียว ซึ่งผมจะไม่ลงรายละเอียด แต่ไปศึกษาเพิ่มเติมกันได้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.tomray.dev&#x2F;nestjs-docker-production&quot;&gt;How to write a NestJS Dockerfile optimized for production&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;เมื่อเสร็จสิ้นกระบวนการ จะได้ขนาด Image ประมาณ 1.18 GB&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;REPOSITORY            TAG           IMAGE ID       CREATED       SIZE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote-state-api      alpine        f42e4b8e75cb   4 days ago    1.18GB
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เมื่อเราเช็คขนาด Image ของ Alpine จะอยู่ที่ 167 MB&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;REPOSITORY            TAG           IMAGE ID       CREATED       SIZE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;node                  18-alpine   8a6b96edfa16   9 days ago     167MB
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แสดงว่าแอพของเราไม่รวม base image จะมีขนาดประมาณ 1 GB อันนี้คือ Nx ที่รวม node_modules ทุก Project ที่อยู่ใน monorepo เดียวกันเลย แสดงว่า devDependencies จะอยู่ที่ประมาณ 700 MB เลยทีเดียว&lt;&#x2F;p&gt;
&lt;h3 id=&quot;taw-yaang-dockerfile&quot;&gt;ตัวอย่าง Dockerfile&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaang-dockerfile&quot; aria-label=&quot;Anchor link for: taw-yaang-dockerfile&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;dockerfile&quot; class=&quot;language-dockerfile z-code&quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; BUILD FOR DEVELOPMENT
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; node:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;18&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;As&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;development&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;curl -f https:&#x2F;&#x2F;get.pnpm.io&#x2F;v6.16.js | node - add --global pnpm
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node . .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpm install --frozen-lockfile
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpx nx run remote-state-server:build:production
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;USER &lt;&#x2F;span&gt;node
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; BUILD FOR PRODUCTION
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; node:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;18&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;As&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;build&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;curl -f https:&#x2F;&#x2F;get.pnpm.io&#x2F;v6.16.js | node - add --global pnpm
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node package.json pnpm-lock.yaml .&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node apps&#x2F;remote-state-server&#x2F;prisma .&#x2F;prisma&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node --from=development &#x2F;app&#x2F;dist&#x2F;apps&#x2F;remote-state-server .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;NODE_ENV production
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpm install --prod --frozen-lockfile
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;USER &lt;&#x2F;span&gt;node
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; PRODUCTION
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; node:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;18-alpine&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;As&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;production&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node --from=build &#x2F;app .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;apk add --update --no-cache openssl1.1-compat curl
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; We don&amp;#39;t have the existing sqlite file
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; So, we will create a fresh sqlite every time when build
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; This migration should be run every time when build
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;npx prisma migrate deploy
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Prepare prima library
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;npx prisma generate
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Clean up with https:&#x2F;&#x2F;github.com&#x2F;tj&#x2F;node-prune
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;curl -sf https:&#x2F;&#x2F;gobinaries.com&#x2F;tj&#x2F;node-prune | sh
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Run cleanup necessary dependencies Ref: Fix npm by https:&#x2F;&#x2F;bobbyhadz.com&#x2F;blog&#x2F;npm-fix-the-upstream-dependency-conflict-installing-npm-packages
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; RUN npm prune --force --legacy-peer-deps --production
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;&#x2F;usr&#x2F;local&#x2F;bin&#x2F;node-prune
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; remove unused dependencies
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; https:&#x2F;&#x2F;tsh.io&#x2F;blog&#x2F;reduce-node-modules-for-better-performance&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; https:&#x2F;&#x2F;medium.com&#x2F;@alpercitak&#x2F;nest-js-reducing-docker-container-size-4c2672369d30
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;rm -rf node_modules&#x2F;rxjs&#x2F;src&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;rm -rf node_modules&#x2F;rxjs&#x2F;bundles&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;rm -rf node_modules&#x2F;rxjs&#x2F;_esm5&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;rm -rf node_modules&#x2F;rxjs&#x2F;_esm2015&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;rm -rf node_modules&#x2F;swagger-ui-dist&#x2F;*.map
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;PORT=3333
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;EXPOSE &lt;&#x2F;span&gt;${PORT}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-dockerfile&quot;&gt;CMD &lt;&#x2F;span&gt;[ &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;node&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;main.js&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; ]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถ้าสังเกตุใน dockerfile จะเห็นได้ว่าผมใช้ &lt;code&gt;prisma generate&lt;&#x2F;code&gt; ใน Alpine ซึ่งโดยปกติเราเวลาใช้ Alpine เรามักจะจัดการทุกอย่างให้เสร็จก่อนใน debian image แล้วค่อย copy file มาที่ Alpine&lt;&#x2F;p&gt;
&lt;p&gt;แต่ Prisma ไม่อนุญาตเรา build ไว้ก่อนใน debian เพราะ OS ไม่ตรงกับที่ runtime ผมเลยจำใจต้องมา build ใน Alpine แทน&lt;&#x2F;p&gt;
&lt;p&gt;ในการรัน Prisma ใน Alpine นั้นจะขาด libary ที่ชื่อว่า &lt;code&gt;openssl1.1-compat&lt;&#x2F;code&gt; ไม่งั้นจะ Error ว่า &lt;strong&gt;&quot;Error: Unable to establish a connection to query-engine-node-api library. It seems there is a problem with your OpenSSL installation!&quot;&lt;&#x2F;strong&gt; ขอบคุณ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;prisma&#x2F;prisma&#x2F;issues&#x2F;14073&quot;&gt;prisma&#x2F;prisma issues#14073&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;step-3-cchadkaar-dependencies-thiiaimekiiywkh-ngkaboprecchkhnan-kaipcchaak-nx&quot;&gt;Step 3: จัดการ dependencies ที่ไม่เกี่ยวข้องกับโปรเจ็คนั้นๆ ออกไปจาก Nx&lt;a class=&quot;zola-anchor&quot; href=&quot;#step-3-cchadkaar-dependencies-thiiaimekiiywkh-ngkaboprecchkhnan-kaipcchaak-nx&quot; aria-label=&quot;Anchor link for: step-3-cchadkaar-dependencies-thiiaimekiiywkh-ngkaboprecchkhnan-kaipcchaak-nx&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ซึ่งการที่จะหาว่าใน Project นั้นใช้ dependenies อะไรบ้างนั้น Nx ไม่ได้ให้ Tool สำหรับหา ดังนั้นเราต้องใช้ tool นอก ซึ่งผมจะใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;depcheck&#x2F;depcheck&quot;&gt;depcheck&lt;&#x2F;a&gt; ในการรันเช็คใน Project นั้นๆ&lt;&#x2F;p&gt;
&lt;p&gt;แต่มันก็ไม่ได้ง่ายแบบนั้น เพราะ Nx สามารถเรียก Library ที่อยู่ภายใน Monorepo เดียวกันได้เลย ดังนั้นเราต้องรัน depcheck ทุก project ที่เกี่ยวข้องทั้งหมด แล้วเราจะหาได้ยังไงว่า Project เราใช้ Libary อะไรบ้าง ในเมื่อมันไม่ได้มี package.json แยกแต่ละ project&lt;&#x2F;p&gt;
&lt;p&gt;เราสามารถหาได้ 2 วิธี&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;เราสามารถใช้ &lt;code&gt;depcheck&lt;&#x2F;code&gt; เพื่อดู &lt;strong&gt;Missing dependencies&lt;&#x2F;strong&gt; ใน Project เรา ส่วนใหญ่แล้ว Missing dependencies จะเป็นการอ้างอิงภายใน monorepo เดียวกัน เพราะมันไม่ได้อยู่ใน package.json ที่อยู่ root ของ repo&lt;&#x2F;li&gt;
&lt;li&gt;เราสามารถใช้ tool ของ Nx ในการ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nx.dev&#x2F;recipes&#x2F;other&#x2F;export-project-graph&quot;&gt;Export Project Graph to JSON&lt;&#x2F;a&gt; ได้โดยใช้ &lt;code&gt;nx graph --file=output.json&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;จากนั้นในบทความหลายๆ ที่ก็แนะนำให้ใช้ &lt;code&gt;npm prune&lt;&#x2F;code&gt; และ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tj&#x2F;node-prune&quot;&gt;node-prune&lt;&#x2F;a&gt; และผมก็ได้ลอง&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;trendyol-tech&#x2F;how-we-reduce-node-docker-image-size-in-3-steps-ff2762b51d5a&quot;&gt;How We Reduce Node Docker Image Size In 3 Steps&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;tsh.io&#x2F;blog&#x2F;reduce-node-modules-for-better-performance&#x2F;&quot;&gt;Honey, I shrunk the node_modules! ...and improved app’s performance in the process. On node module size&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;และเมื่อเราได้ dependencies ของทุก project ที่เกี่ยวข้องกันแล้ว เราก็เอา package.json ในแต่ละ project มารวมกันที่เดียวเรา npm install ใหม่เพื่อให้ได้ lock file มา  แล้วเอา 2 files นี้ไป build ใน docker image&lt;&#x2F;p&gt;
&lt;p&gt;และเมื่อผมทำมาทั้งหมดที่ว่ามาแล้ว ก็จะเหลือขนาด image ประมาณ 831 MB แสดงว่าขนาดแอพเราจะอยู่ที่ 664 MB ซึ่งก็ยังเยอะอยู่ดี&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;REPOSITORY            TAG             IMAGE ID       CREATED       SIZE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote-state-api      alpine-unused   907254a67d28   4 days ago    831MB
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ใน Step นี้จะใช้ dockerfile เดียวกันกับ step ที่แล้ว&lt;&#x2F;p&gt;
&lt;h2 id=&quot;step-4-bundle-nestjs-odyaich-esbuild&quot;&gt;Step 4: Bundle Nestjs โดยใช้ esbuild&lt;a class=&quot;zola-anchor&quot; href=&quot;#step-4-bundle-nestjs-odyaich-esbuild&quot; aria-label=&quot;Anchor link for: step-4-bundle-nestjs-odyaich-esbuild&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จริง ผมเคยมีความพยายามจะ Bundle Nestjs ด้วย esbuild หลายครั้งแล้ว ซึ่งเป็นวิธีเดียวกันกับเวลาเรา bundle JS เพื่อใช้ Browser เลย โดยที่เราไม่ต้องใส่ ืnode_modules ลงไปใน docker images เลย เย้ๆ จึงทำให้ขนาดของ Nestjs แอพที่ bundle แล้วจะอยู่ที่ 2.3 MB เท่านั้นเอง โอ้ว เล็กมากๆ&lt;&#x2F;p&gt;
&lt;p&gt;แต่มัน build แบบ bundle ไม่ผ่านครับ เพราะมันจะบอกว่าเราไม่ได้ลง packages พวก &lt;code&gt;cache-manager&lt;&#x2F;code&gt;, &lt;code&gt;@nestjs&#x2F;microservices&lt;&#x2F;code&gt;, &lt;code&gt;class-transformer&#x2F;storage&lt;&#x2F;code&gt; ไว้ ทำให้มันหาไม่เจอ&lt;&#x2F;p&gt;
&lt;p&gt;เพราะว่า Nestjs มีการเรียกหา packages พวกนั้นด้วย แต่เราไม่ได้ใช้งานนี่สิ ทำไมเราต้องลง ซึ่งใน esbuild เองเราสามารถเอา package ที่เราไม่ต้องการออกจาก bundle ให้ (ก็คือถ้าไม่อยู่ใน bundle มันจะไปหาใน node_modules แทน) โดยการใช้ config ประมาณนี้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;BuildOptions&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;esbuild&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;buildConfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;BuildOptions&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;   &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;external&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;cache-manager&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;@nestjs&#x2F;microservices&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;class-transformer&#x2F;storage&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;buildConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แต่ว่าเราก็ไม่สามารถทำงานได้อีก รอบนี้ดูเหมือน Depedency Injection ของ Nestjs ไม่ทำงาน ต้องขอบคุณ คุณ Anton Golub ที่เขียน blog เรื่อง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;dev.to&#x2F;antongolub&#x2F;nestjs-esbuild-workarounds-99i&quot;&gt;NestJS + esbuild workarounds&lt;&#x2F;a&gt; ซึ่งเค้าได้อธิบายว่า esbuild จะไม่ได้ bundle พวก decorator ให้เรา ดังนั้นเค้าจึงเขียน plugin ใน esbuild ที่ชื่อ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;anatine&#x2F;esbuildnx&quot;&gt;@anatine&#x2F;esbuild-decorators&lt;&#x2F;a&gt; เพื่อมาจัดการตรงนี้&lt;&#x2F;p&gt;
&lt;p&gt;และผมก็เจอปัญหาลักษณะเดียวกันกับ Prisma เช่นกัน ผมเลยจึงเอา &lt;code&gt;prisma&lt;&#x2F;code&gt; และ &lt;code&gt;@prisma&#x2F;client&lt;&#x2F;code&gt; ออกจาก bundle ด้วย แล้วค่อยไปลงใหม่ใน docker build แทน&lt;&#x2F;p&gt;
&lt;p&gt;โดยในที่สุดก็จะได้ image ขนาด 376 MB หรือถ้าตัด base image ออก จะเหลือ 209 MB&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;REPOSITORY            TAG            IMAGE ID       CREATED       SIZE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote-state-api      alpine-bundle  022a0feda515   4 days ago    376MB
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;taw-yaang-dockerfile-1&quot;&gt;ตัวอย่าง Dockerfile&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaang-dockerfile-1&quot; aria-label=&quot;Anchor link for: taw-yaang-dockerfile-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;custom esbuild config&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;fs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;fs&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;path&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;path&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;program&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;commander&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;BuildOptions&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;esbuild&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;typecheckPlugin&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;@jgoz&#x2F;esbuild-plugin-typecheck&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-import z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-ts&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-ts&quot;&gt;esbuildDecorators&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-ts&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;@anatine&#x2F;esbuild-decorators&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-variable z-object z-process z-ts&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-process z-ts&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;outfile&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-promise z-ts&quot;&gt;resolve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;output.js&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;tsconfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-promise z-ts&quot;&gt;resolve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;tsconfig.json&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;isVerbose&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-variable z-object z-process z-ts&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-process z-ts&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;verbose&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-ts&quot;&gt;===&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;true&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-true z-ts&quot;&gt;true&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-false z-ts&quot;&gt;false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-interface z-ts&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-ts&quot;&gt;ICommandOption&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;watch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;boolean&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-interface z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;program&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;description&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Script for building atom CLI&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;option&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;-w, --watch&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Enable watch mode&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;option&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;-o, --output &amp;lt;path&amp;gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;output file&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;action&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-async z-ts&quot;&gt;async&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;opts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;program&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;opts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ICommandOption&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;watch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;watch&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;??&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-false z-ts&quot;&gt;false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;output&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-promise z-ts&quot;&gt;resolve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;opts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;dist&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;program&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;parse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-object z-process z-ts&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-process z-ts&quot;&gt;argv&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-async z-ts&quot;&gt;async&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;option&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ICommandOption&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;BuildOptions&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;entryPoints&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;apps&#x2F;remote-state-server&#x2F;src&#x2F;main.ts&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;bundle&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-true z-ts&quot;&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;platform&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;node&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;node18&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;es2021&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;outdir&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;option&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;tsconfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;plugins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;typecheckPlugin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;esbuildDecorators&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;tsconfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;option&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;buildConfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;BuildOptions&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;external&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;commander&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;cache-manager&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;@nestjs&#x2F;microservices&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;prisma&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;@prisma&#x2F;client&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;kafkajs&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;mqtt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;amqplib&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;amqp-connection-manager&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;nats&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;@grpc&#x2F;grpc-js&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;@grpc&#x2F;proto-loader&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;@nestjs&#x2F;websockets&#x2F;socket-module&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;class-transformer&#x2F;storage&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-spread z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;developConfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;BuildOptions&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-spread z-ts&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;external&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;commander&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;watch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;onRebuild&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;option&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;watch&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;developConfig&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;buildConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;onRebuild&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;error&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-return z-type z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;void&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;error&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;watch build failed&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;isVerbose&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;error&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;else&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Date&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toISOString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt; watch build succeeded &lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;project.json&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json z-code&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-js&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-json&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; project.json
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;targets&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;build-esbuild&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;executor&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;nx:run-commands&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;options&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;commands&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;          &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;tsx src&#x2F;scripts&#x2F;build.ts --output &amp;#39;..&#x2F;..&#x2F;dist&#x2F;apps&#x2F;remote-state-server&amp;#39;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;parallel&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cwd&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;apps&#x2F;remote-state-server&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Dockerfile&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dockerfile&quot; class=&quot;language-dockerfile z-code&quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; BUILD
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; node:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;18&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;As&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;development&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;curl -f https:&#x2F;&#x2F;get.pnpm.io&#x2F;v6.16.js | node - add --global pnpm
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node . .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpm install --frozen-lockfile
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpx nx run remote-state-server:build-esbuild
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;USER &lt;&#x2F;span&gt;node
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Install Dependencies
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; node:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;18&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;As&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;build&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;curl -f https:&#x2F;&#x2F;get.pnpm.io&#x2F;v6.16.js | node - add --global pnpm
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node apps&#x2F;remote-state-server&#x2F;prisma .&#x2F;prisma&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node --from=development &#x2F;app&#x2F;dist&#x2F;apps&#x2F;remote-state-server .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;NODE_ENV production
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpm install @prisma&#x2F;client@^4.7.1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;USER &lt;&#x2F;span&gt;node
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; PRODUCTION
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; node:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;18-alpine&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;As&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;production&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node --from=build &#x2F;app .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; For Prisma client in Alpine
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Fix &amp;quot;Error: Unable to establish a connection to query-engine-node-api library. It seems there is a problem with your OpenSSL installation!&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Ref: https:&#x2F;&#x2F;github.com&#x2F;prisma&#x2F;prisma&#x2F;issues&#x2F;14073
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;apk add --update --no-cache openssl1.1-compat
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; We don&amp;#39;t have the existing sqlite file
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; So, we will create a fresh sqlite every time when build
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; This migration should be run every time when build
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;npx prisma migrate deploy
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Prepare prima library
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;npx prisma generate
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;PORT=3333
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;EXPOSE &lt;&#x2F;span&gt;${PORT}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-dockerfile&quot;&gt;CMD &lt;&#x2F;span&gt;[ &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;node&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;main.js&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; ]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;step-5-aich-alpine-eplaa-aelalbaiflaimcchamepn-k&quot;&gt;Step 5: ใช้ Alpine เปล่าๆ และลบไฟล์ไม่จำเป็นออก&lt;a class=&quot;zola-anchor&quot; href=&quot;#step-5-aich-alpine-eplaa-aelalbaiflaimcchamepn-k&quot; aria-label=&quot;Anchor link for: step-5-aich-alpine-eplaa-aelalbaiflaimcchamepn-k&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ใน Step นี้ เปลี่ยนไปใช้ alpine base image แล้วก็ลง nodejs เอง ลบไฟล์ที่ไม่จำเป็นออกทั้งหมด แล้วก็ติดตั้ง Prisma version โดยอ่านจาก &lt;code&gt;package.json&lt;&#x2F;code&gt; ไฟล์ รวมถึง set user เป็น non root&lt;&#x2F;p&gt;
&lt;p&gt;แล้วก็ใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;wagoodman&#x2F;dive&quot;&gt;dive&lt;&#x2F;a&gt; ในการวิเคราะห์ในแต่ละ Layer ว่ามีไฟล์อะไรอยู่บ้าง จะได้ลบไฟล์ที่ไม่ได้ใช้ออกไป&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dockerfile&quot; class=&quot;language-dockerfile z-code&quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; BUILD FOR PRODUCTION
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; node:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;18&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;As&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;build&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;curl -f https:&#x2F;&#x2F;get.pnpm.io&#x2F;v6.16.js | node - add --global pnpm
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node . .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpm install --frozen-lockfile
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;pnpx nx run remote-state-server:build-esbuild
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;USER &lt;&#x2F;span&gt;node
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; PRODUCTION
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt;##################
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Not Natively support ARM64 (M1)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; alpine:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;3.17&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;As&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;production&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;PORT=3333
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;NODE_VERSION 18.12.1-r0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;NPM_VERSION 9.1.2-r0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;ENV &lt;&#x2F;span&gt;OPENSSL_COMPAT_VERSION 1.1.1s-r0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node package.json .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node apps&#x2F;remote-state-server&#x2F;prisma .&#x2F;prisma&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --chown=node:node --from=build &#x2F;app&#x2F;dist&#x2F;apps&#x2F;remote-state-server .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;apk add --update --no-cache nodejs=$NODE_VERSION
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;apk add --update --no-cache \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; For getting node-prune
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  curl \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; For Prisma client in Alpine
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Fix &amp;quot;Error: Unable to establish a connection to query-engine-node-api library. It seems there is a problem with your OpenSSL installation!&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Ref: https:&#x2F;&#x2F;github.com&#x2F;prisma&#x2F;prisma&#x2F;issues&#x2F;14073
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  openssl1.1-compat=$OPENSSL_COMPAT_VERSION \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  npm=$NPM_VERSION \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; npx will look the local node_modules first, if not it will install globally
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Ref: https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;22420564&#x2F;install-only-one-package-from-package-json
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; PRISMA_CLIENT_VERSION=$(node -pe &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;require(&amp;#39;.&#x2F;package&amp;#39;).dependencies[&amp;#39;@prisma&#x2F;client&amp;#39;]&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;) \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; PRISMA_VERSION=$(node -pe &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;require(&amp;#39;.&#x2F;package&amp;#39;).dependencies[&amp;#39;prisma&amp;#39;]&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;) \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; We don&amp;#39;t need package.json anymore
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; rm -rf package.json \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; npm install @prisma&#x2F;client@$PRISMA_CLIENT_VERSION \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; npm install -D prisma@$PRISMA_VERSION \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; We don&amp;#39;t have the existing sqlite file
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; So, we will create a fresh sqlite every time when build
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; This migration should be run every time when build
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; npx prisma migrate deploy \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Prepare prisma library
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; If we don&amp;#39;t have package.json, prisma will create for you, and create a local node_modules
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; npx prisma generate \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Prune non-used files
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; npm prune --production \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Clean Prisma non-used files https:&#x2F;&#x2F;github.com&#x2F;prisma&#x2F;prisma&#x2F;issues&#x2F;11577
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; rm -rf node_modules&#x2F;.cache&#x2F; \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; rm -rf node_modules&#x2F;@prisma&#x2F;engines&#x2F; \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; rm -rf node_modules&#x2F;@prisma&#x2F;engines-version \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; rm -rf node_modules&#x2F;prisma \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Remove cache
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; rm -rf &#x2F;root&#x2F;.cache&#x2F; \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; rm -rf &#x2F;root&#x2F;.npm&#x2F; \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-dockerfile&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Remove all unused dependecies
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;  &amp;amp;&amp;amp; apk del openssl1.1-compat npm curl
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;EXPOSE &lt;&#x2F;span&gt;${PORT}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; Create a group and user
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;addgroup -g 1000 node \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;    &amp;amp;&amp;amp; adduser -u 1000 -G node -s &#x2F;bin&#x2F;sh -D node
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;USER &lt;&#x2F;span&gt;node
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-dockerfile&quot;&gt;CMD &lt;&#x2F;span&gt;[ &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;node&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;, &lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;main.js&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; ]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;srup&quot;&gt;สรุป&lt;a class=&quot;zola-anchor&quot; href=&quot;#srup&quot; aria-label=&quot;Anchor link for: srup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;โดยในที่สุดก็จะได้ image ขนาด 77 MB เมื่อตัด runtime ทุกอย่างออก ตัว node app จะเหลือที่ 25 MB (ดูใน dive)&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;REPOSITORY            TAG            IMAGE ID       CREATED           SIZE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote-state-api      alpine-unused  12b08b0bfc1f   8 seconds ago     77.8MB
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;พอได้ใช้ &lt;code&gt;dive&lt;&#x2F;code&gt; ส่องดูก็พบว่า ขนาดเล็กกำลังดีเลย&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;reduce-nestjs-docker-image-size-with-esbuild-bundle&#x2F;final-image-with-dive.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ป.ล. ได้มีการลองใช้ Distroless ของ Google ด้วยแต่ยังติดปัญหากับ Prisma ถ้าใครรู้วิธีก็มาแชร์กันได้น้าา&lt;&#x2F;p&gt;
&lt;h2 id=&quot;acknowledgement&quot;&gt;Acknowledgement&lt;a class=&quot;zola-anchor&quot; href=&quot;#acknowledgement&quot; aria-label=&quot;Anchor link for: acknowledgement&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ขอบคุณคุณ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.facebook.com&#x2F;neutrons&quot;&gt;Neutron Soutmun&lt;&#x2F;a&gt; ใน Facebook Group Docker in Thai มากๆ เลยคับ พอดีไม่ได้จับ Docker นาน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.facebook.com&#x2F;photo?fbid=10230189576151414&amp;amp;set=gm.6041709002535607&amp;amp;idorvanity=858633044176588&quot;&gt;เลยสงสัยว่าทำไมลบไฟล์ใน Dockerfile ไปแล้ว ทำไมขนาดของ image ถึงไม่เล็กลง&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Docker image จะทำ RUN บน storage layer คนละ layer ครับ
layer ที่ทำผ่านไปแล้ว ด้วย RUN ก่อนหน้า จะคงอยู่อย่างนั้น เปลี่ยนแปลงไม่ได้ ด้วย RUN ที่ตามหลังมาครับ&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าคาดหวังจะให้ files ถูกลบ ต้องทำภายใน RUN หรือ layer เดียวกันกับ layer ที่ files นั้น ๆ ถูกเพิ่มเข้ามาครับ
RUN touch test.txt &amp;amp;&amp;amp; rm -rf test.txt
By &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.facebook.com&#x2F;neutrons&quot;&gt;Neutron Soutmun&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;aehlng-aang-ing&quot;&gt;แหล่งอ้างอิง&lt;a class=&quot;zola-anchor&quot; href=&quot;#aehlng-aang-ing&quot; aria-label=&quot;Anchor link for: aehlng-aang-ing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;docker&quot;&gt;Docker&lt;a class=&quot;zola-anchor&quot; href=&quot;#docker&quot; aria-label=&quot;Anchor link for: docker&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Multi-Stage: https:&#x2F;&#x2F;www.tomray.dev&#x2F;nestjs-docker-production&lt;&#x2F;li&gt;
&lt;li&gt;Best Practice: https:&#x2F;&#x2F;snyk.io&#x2F;blog&#x2F;10-best-practices-to-containerize-nodejs-web-applications-with-docker&#x2F;&lt;&#x2F;li&gt;
&lt;li&gt;Reduce File Size Node.js: https:&#x2F;&#x2F;medium.com&#x2F;trendyol-tech&#x2F;how-we-reduce-node-docker-image-size-in-3-steps-ff2762b51d5a&lt;&#x2F;li&gt;
&lt;li&gt;Honey, I shrunk the node_modules! ...and improved app’s performance in the process. On node module size: https:&#x2F;&#x2F;tsh.io&#x2F;blog&#x2F;reduce-node-modules-for-better-performance&#x2F;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;docker-read-more&quot;&gt;Docker Read more&lt;a class=&quot;zola-anchor&quot; href=&quot;#docker-read-more&quot; aria-label=&quot;Anchor link for: docker-read-more&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;medium.com&#x2F;swlh&#x2F;nx-nestjs-react-docker-deploys-928a55fc19fd&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;www.codefeetime.com&#x2F;post&#x2F;using-docker-compose-with-nx-monorepo-for-multi-apps-development&#x2F;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;kube&quot;&gt;Kube&lt;a class=&quot;zola-anchor&quot; href=&quot;#kube&quot; aria-label=&quot;Anchor link for: kube&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;creotip.io&#x2F;posts&#x2F;nx-monorepo-running-microservices-locally-with-docker-kubernetes&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;bff&quot;&gt;BFF&lt;a class=&quot;zola-anchor&quot; href=&quot;#bff&quot; aria-label=&quot;Anchor link for: bff&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;bff-demo&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>TypeScript 4.9: มาใช้ satisfies เพื่อทำให้ Type ถูกต้องมากขึ้นกันเถอะ</title>
		<published>2022-11-23T00:00:00+00:00</published>
		<updated>2022-11-23T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/typescript-satisfies/" type="text/html"/>
		<id>https://thadaw.com/posts/typescript-satisfies/</id>
		<content type="html">&lt;p&gt;อย่างที่รู้กันว่าตอนนี้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;devblogs.microsoft.com&#x2F;typescript&#x2F;announcing-typescript-4-9&#x2F;&quot;&gt;TypeScript 4.9&lt;&#x2F;a&gt; release ออกมาแล้ว
มี feature หนึ่งที่น่าสนใจคือ &lt;code&gt;satisfies&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ex-1-safe-upcast&quot;&gt;Ex.1 - Safe Upcast&lt;a class=&quot;zola-anchor&quot; href=&quot;#ex-1-safe-upcast&quot; aria-label=&quot;Anchor link for: ex-1-safe-upcast&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;RGB&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;readonly&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-tuple z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-label z-ts&quot;&gt;red&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-label z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-label z-ts&quot;&gt;green&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-label z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-label z-ts&quot;&gt;blue&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-label z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Color&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;RGB&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;string&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;myColor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;red&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;satisfies&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Color&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; works&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;myIncorrectColor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;100&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;satisfies&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Color&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; throws error&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;myColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;toUpperCase&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; valid operation as myColor is a string&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;ex-2-safe-upcast&quot;&gt;Ex.2 - Safe Upcast&lt;a class=&quot;zola-anchor&quot; href=&quot;#ex-2-safe-upcast&quot; aria-label=&quot;Anchor link for: ex-2-safe-upcast&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Animal&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;kind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cat&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;meows&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;true&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;kind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dog&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;barks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-builtin z-ts&quot;&gt;true&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;p&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;kind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cat&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-ts&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Animal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Missing meows!&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;kind&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-ts&quot;&gt;===&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dog&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;else&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;meows&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Reported &amp;#39;true&amp;#39;, actually &amp;#39;undefined&amp;#39;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;solution&quot;&gt;Solution&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution&quot; aria-label=&quot;Anchor link for: solution&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;p&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;kind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cat&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;meows&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-true z-ts&quot;&gt;true&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;satisfies&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Animal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;ex-3-property-name-constraining&quot;&gt;Ex.3 - Property Name Constraining&lt;a class=&quot;zola-anchor&quot; href=&quot;#ex-3-property-name-constraining&quot; aria-label=&quot;Anchor link for: ex-3-property-name-constraining&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Keys&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;b&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;c&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;d&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;p2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;8&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Should error, &amp;#39;x&amp;#39; isn&amp;#39;t in &amp;#39;Keys&amp;#39;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Should be OK -- retain info that a is number and b is string&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;p2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;toFixed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;p2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-ts&quot;&gt;length&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Should error even though &amp;#39;d&amp;#39; is in &amp;#39;Keys&amp;#39;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;p2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;solution-1&quot;&gt;Solution&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution-1&quot; aria-label=&quot;Anchor link for: solution-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;p2&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;satisfies&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Partial&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-bitwise z-shift z-ts&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;ex-4-property-name-fulfillment&quot;&gt;EX.4 - Property Name Fulfillment&lt;a class=&quot;zola-anchor&quot; href=&quot;#ex-4-property-name-fulfillment&quot; aria-label=&quot;Anchor link for: ex-4-property-name-fulfillment&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Keys2&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;b&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;c&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-ts&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;d&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;p3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-true z-ts&quot;&gt;true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Should error because &amp;#39;d&amp;#39; is missing&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Should be OK&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;t&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;boolean&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;p3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;solution-2&quot;&gt;Solution&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution-2&quot; aria-label=&quot;Anchor link for: solution-2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;p3&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;satisfies&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;unknown&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts z-code&quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-type z-ts&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-ts&quot;&gt;Color2&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;r&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;g&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt; &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-ts&quot;&gt;number&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; All of these should be Colors, but I only use some of them here.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;Palette&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;white&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;r&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;g&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;black&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;r&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;g&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; &amp;lt;- oops! &amp;#39;d&amp;#39; in place of &amp;#39;b&amp;#39;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;blue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;r&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;g&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;255&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;Palette2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;white&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;r&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;g&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;black&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;r&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;g&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; &amp;lt;- error is now detected&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;blue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;r&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;g&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;255&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;satisfies&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Record&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;Color2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ขอบคุณตัวอย่างจาก  https:&#x2F;&#x2F;github.com&#x2F;microsoft&#x2F;TypeScript&#x2F;issues&#x2F;47920&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sueksaaephim&quot;&gt;ศึกษาเพิ่ม&lt;a class=&quot;zola-anchor&quot; href=&quot;#sueksaaephim&quot; aria-label=&quot;Anchor link for: sueksaaephim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=6uJeT7y6CCo&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Dealing with more than 100 secrets on GitHub Actions using Mozilla SOPS and Azure Key Vault</title>
		<published>2022-05-07T00:00:00+00:00</published>
		<updated>2022-05-07T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/100-secrets-github-actions-sops-with-azure-key-vault/" type="text/html"/>
		<id>https://thadaw.com/posts/100-secrets-github-actions-sops-with-azure-key-vault/</id>
		<content type="html">&lt;h2 id=&quot;talks-info&quot;&gt;Talks Info&lt;a class=&quot;zola-anchor&quot; href=&quot;#talks-info&quot; aria-label=&quot;Anchor link for: talks-info&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Event: Global Azure Thailand.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;100-secrets-github-actions-sops-with-azure-key-vault&quot;&gt;Demo Repo in Talk&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;sops-with-azure-keyvault-secrets&quot;&gt;SOPS for Azure Key Vault Boilerplate on GitHub&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;ก่อนที่จะอ่านบทความนี้ควรที่จะเข้าใจการใช้งาน GitHub Actions เบื้องต้นก่อน&lt;&#x2F;p&gt;
&lt;h1 id=&quot;1-introduction&quot;&gt;1. Introduction&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-introduction&quot; aria-label=&quot;Anchor link for: 1-introduction&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;เชื่อว่าหลายๆ คนมีการอัพโหลด secret ไปที่ GitHub Secrets เพื่อที่จะ deploy ไปที่ server&lt;&#x2F;p&gt;
&lt;p&gt;แต่ประเด็นคือ ใน 1 GitHub Action repo เราใช้ secret ของ GitHub Action ได้ไม่เกิน 100 ตัว เพื่อแก้ปัญหาดังกล่าว เราเลยมีทางออกประมาณ 3 วิธี&lt;&#x2F;p&gt;
&lt;h2 id=&quot;possible-solution&quot;&gt;Possible Solution&lt;a class=&quot;zola-anchor&quot; href=&quot;#possible-solution&quot; aria-label=&quot;Anchor link for: possible-solution&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;ย้ายไปสร้างที่ Organization แทน มันใส่ได้ 1,000 ตัว เพราะว่า secret จะไปเห็นที่ repo อื่นๆ ด้วย จึงไม่ผ่านเรื่อง security&lt;&#x2F;li&gt;
&lt;li&gt;สร้าง Service Principal ของแต่ละ resource group แล้ว ตอน deploy ให้ไป download publish profile ทุกครั้ง แทน เพื่อลดจำนวน secrets แต่วิธีการนี้ ก็ปัญหาเรื่อง security เช่นกัน เพราะ เรามี secret  ที่มีสิทธิสูงเกินความจำเป็น ถ้าใช้หลักการของ zero trust เราควรทำให้ secret มีสิทธิ์เพียงแค่เท่าที่ใช้งานเท่านั้น (Principle of least privilege)&lt;&#x2F;li&gt;
&lt;li&gt;เราจะเก็บ Decryption Key ใน Github secrets โดยแยกแต่ละ Environment หรือ group ที่เรากำหนดไว้ เวลาจะใช้ ก็ decrypt ออกมา ซึ่งไฟล์ encrypted secrets อยู่ใน Private Repo แทน อ่านเพิ่ม &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;actions&#x2F;security-guides&#x2F;encrypted-secrets#limits-for-secrets&quot;&gt;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;actions&#x2F;security-guides&#x2F;encrypted-secrets#limits-for-secrets&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mozilla&#x2F;sops&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;mozilla&#x2F;sops&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;our-solution&quot;&gt;Our Solution&lt;a class=&quot;zola-anchor&quot; href=&quot;#our-solution&quot; aria-label=&quot;Anchor link for: our-solution&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เราเลือกที่จะไปทางข้อ Solution ข้อที่ 3 โดยเราเลือกใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mozilla&#x2F;sops&quot;&gt;Mozilla SOPS&lt;&#x2F;a&gt; ซึ่งเป็น Tools ที่เป็นที่นิยมมากๆ ในการจัดการ secrets โดยใช้วิธีการ symmetric encyption ไฟล์ Yaml เพื่อจะ encrypt secrets ต่างๆ โดย SOPS support การ Encrypt จาก Cloud ไม่ว่าจะเป็น Azure, AWS, หรือ GCP รวมถึง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.vaultproject.io&#x2F;&quot;&gt;HashiCorp Vault&lt;&#x2F;a&gt; ด้วย และยังสามารถใช้ Local Encrypt จาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;FiloSottile&#x2F;age&quot;&gt;Age&lt;&#x2F;a&gt; และ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.openpgp.org&#x2F;&quot;&gt;PGP&lt;&#x2F;a&gt; ได้อีกด้วย&lt;&#x2F;p&gt;
&lt;h3 id=&quot;saaehtuthiieluue-kaich-sops&quot;&gt;สาเหตุที่เลือกใช้ SOPS&lt;a class=&quot;zola-anchor&quot; href=&quot;#saaehtuthiieluue-kaich-sops&quot; aria-label=&quot;Anchor link for: saaehtuthiieluue-kaich-sops&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;มีการพูดถึง SOPS ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.cncf.io&#x2F;&quot;&gt;Cloud Native Computing Foundation (CNCF)&lt;&#x2F;a&gt; เกี่ยวกับการจัดการ Secrets &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.cncf.io&#x2F;blog&#x2F;2021&#x2F;04&#x2F;22&#x2F;revealing-the-secrets-of-kubernetes-secrets&#x2F;&quot;&gt;สำหรับ Kubernates&lt;&#x2F;a&gt; และอยู่ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;radar.cncf.io&#x2F;2021-02-secrets-management&quot;&gt;CNCF Radar 2021 ระดับ Assess&lt;&#x2F;a&gt; และอยู่ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.thoughtworks.com&#x2F;en-th&#x2F;radar&#x2F;tools&#x2F;mozilla-sops&quot;&gt;thoughtworks Technology Radar 2021 ระดับ Assess&lt;&#x2F;a&gt; เครื่องมือ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;fluxcd.io&#x2F;docs&#x2F;guides&#x2F;mozilla-sops&#x2F;&quot;&gt;Flux CD ก็เขียนคู่มือการใช้งาน SOPS ไว้&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;แต่ SOPS เองก็มีประเด็นต้องพิจารณาเพิ่มเติมด้วย&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;เราจะเก็บ Cipher text (Encrypted data) ไว้ที่ไหนถึงจะปลอดภัย&lt;&#x2F;li&gt;
&lt;li&gt;เรื่องของ Key Rotation อาจจะต้องการจัดเอง&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;เราไม่สามารถเก็บ secrets ทั้งหมดได้ใน github Secrets เพราะจากจำนวน secrets ที่เยอะ จึงไม่สามารถเก็บใน 1 Github Secrets ที่มีขนาดไม่เกิน 64 KB&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Secrets are limited to 64 KB in size. To use secrets that are larger than 64 KB, you can store encrypted secrets in your repository and save the decryption passphrase as a secret on GitHub. อ่านเพิ่ม &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;actions&#x2F;security-guides&#x2F;encrypted-secrets#limits-for-secrets&quot;&gt;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;actions&#x2F;security-guides&#x2F;encrypted-secrets#limits-for-secrets&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ดังนั้น ถ้าเราเก็บ SOPS Encrypted Secrets ตรงๆ ใน GitHub Secrets ไม่ได้เนื่องจากขนาดเกิน การเก็บ Encrypted Secrets ใน Git Repo ก็ทางเลือกหนึ่งที่พอรับได้ แต่สิ่งที่ต้องเผชิญต่อไปคือ Internal Threat&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thaangeluue-k-uuen-ephuue-pidch-ngohweruue-ng-internal-treat&quot;&gt;ทางเลือกอื่นๆ เพื่อปิดช่องโหว่เรื่อง Internal Treat&lt;a class=&quot;zola-anchor&quot; href=&quot;#thaangeluue-k-uuen-ephuue-pidch-ngohweruue-ng-internal-treat&quot; aria-label=&quot;Anchor link for: thaangeluue-k-uuen-ephuue-pidch-ngohweruue-ng-internal-treat&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ถ้าการใช้ SOPS อาจจะยังไม่ตอบโจทย์เรื่องความปลอดภัยเพียงพอ เราอาจจะต้องใช้ External Secret Management Tool เช่น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.vaultproject.io&#x2F;&quot;&gt;HashiCorp Vault&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;แต่สิ่งที่พิจารณาเพิ่มเติมคือ เรื่อง External Threat แทนที่จะเป็นเรื่องของ Internal Threat เวลาใช้ SOPS เก็บ secrets ใน Git Repo&lt;&#x2F;p&gt;
&lt;p&gt;ดังนั้น การที่ทำให้อุดช่องโหว่เรื่อง External Threat คือการทำ Private Connection ระหว่าง HashiCorp Vault Server และ GitHub Action Runner แทน ซึ่งเราจะต้อง Setup Self-Host GitHub Action Runner ขึ้นมาเอง และตั้งค่าให้อยู่ภายใน Private Network เดียวกันกับ HashiCorp Vault Server ดูตัวอย่างได้ใน &lt;strong&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=rhB72KFiL48&quot;&gt;Secure GitOps Workflows with GitHub Actions and HashiCorp Vault&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าเราจะเชื่อมต่อ HashiCorp ******Cloud Platform (HCP) กับ Cloud AWS แบบ Private connection เราสามารถใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;learn.hashicorp.com&#x2F;tutorials&#x2F;cloud&#x2F;amazon-peering-hcp?in=vault&#x2F;cloud-ops&quot;&gt;AWS VPC&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;แต่สำหรับ Azure เองยังไม่ support HCP เราอาจจะต้องตั้งค่า deploy vault server เอง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;our-final-decision&quot;&gt;Our Final Decision&lt;a class=&quot;zola-anchor&quot; href=&quot;#our-final-decision&quot; aria-label=&quot;Anchor link for: our-final-decision&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เนื่องจากข้อจำกัดทางด้านเวลา และทรัพยากรที่เรามี เราจึงเลือกที่เก็บ SOPS encrypted secrets ใน Git Repo แทน จึงทำให้เราต้องมาพิจารณาเรื่อง internal threat แทน และขอไม่รับ External Threat มาเพิ่ม&lt;&#x2F;p&gt;
&lt;h1 id=&quot;2-kaaraichngaan-sops-dwy-age-encryption&quot;&gt;2. การใช้งาน SOPS ด้วย Age Encryption&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-kaaraichngaan-sops-dwy-age-encryption&quot; aria-label=&quot;Anchor link for: 2-kaaraichngaan-sops-dwy-age-encryption&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mozilla&#x2F;sops#22encrypting-using-age&quot;&gt;ใน Docs ของ SOPS ไม่แนะนำให้ใช้ PGP แล้ว ให้เปลี่ยนมาใช้ Age Encryption แทน&lt;&#x2F;a&gt; โดย Age Encryption ใช้เป็น X25519 is an elliptic curve &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Diffie%E2%80%93Hellman_key_exchange&quot;&gt;Diffie-Hellman key exchange&lt;&#x2F;a&gt; using &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Curve25519&quot;&gt;Curve25519&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Install age via brew&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;brew&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; install age&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Generate Age Key&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;age-keygen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; key.txt&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The contain in file &lt;code&gt;key.txt&lt;&#x2F;code&gt; :&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; created: 2022-04-11T15:36:32+07:00&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; public key: age1js5yl37ghup68pzf8f2kutf6xtuwc4m6lpha0llgmcup93q3sp9qtfwvr8&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;AGE-SECRET-KEY-15YXVYTPWNT4UF3KY05K27LZN2SAT83SJKX7UH4MXQEQAWRWPFNYSDHK860&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;DO NOT PUBLISH AGE SECRET KEY&lt;&#x2F;strong&gt; (This is for example in this repo only)&lt;&#x2F;p&gt;
&lt;p&gt;Encrypt&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sops&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;encrypt&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;age&lt;&#x2F;span&gt; age1js5yl37ghup68pzf8f2kutf6xtuwc4m6lpha0llgmcup93q3sp9qtfwvr8 examples&#x2F;data.yaml &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; examples&#x2F;data.age-enc.yaml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เราก็ได้ไฟล์ &lt;code&gt;data.age-enc.yaml&lt;&#x2F;code&gt;  ที่ถูกเข้ารหัสแล้ว เราก็นำไฟล์นี้ Commit ขึ้น Git Repo ได้เลย&lt;&#x2F;p&gt;
&lt;p&gt;อันนี้เป็นตัวอย่างไฟล์ SOPS ที่ถูก Encrypt แล้ว&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;100-secrets-github-actions-sops-with-azure-key-vault&#x2F;Screen_Shot_2565-04-14_at_13.24.48.png&quot; alt=&quot;Screen Shot 2565-04-14 at 13.24.48.png&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;หลังจากนั้น ตั้งค่า GitHub Secret ด้วย Age Secret key&lt;&#x2F;p&gt;
&lt;p&gt;ตัวอย่างการใช้งาน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;steps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;actions&#x2F;checkout@v3&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;mildronize&#x2F;actions-get-secret-sops@v1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;sops&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;examples&#x2F;data.age-enc.yaml&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Encrypted SOPS yaml path
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;property-path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;.scope_a.app_service.app1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; yq&#x2F;jq expression syntax for getting a particular value
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;decrypting-key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets.Age_SOPS_github_action }}&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Age Secret Key
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;sops-version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;3.7.2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;echo &amp;quot;${{ steps.sops.outputs.secret }}&amp;quot;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;ในการใช้งาน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;marketplace&#x2F;actions&#x2F;get-secrets-from-encrypted-sops&quot;&gt;mildronize&#x2F;actions-get-secret-sops&lt;&#x2F;a&gt; จะต้องกำหนด &lt;code&gt;property-path&lt;&#x2F;code&gt; สำหรับเข้าถึง secret ที่เราต้องการผ่าน path ของ yaml ไฟล์ โดยใช้ syntax ของ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;stedolan.github.io&#x2F;jq&#x2F;&quot;&gt;jq&lt;&#x2F;a&gt; หรือ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mikefarah&#x2F;yq&quot;&gt;yq&lt;&#x2F;a&gt; ก็ได้&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;การ Decrypt ให้เราใช้ Age Secret key ตั้งค่าไว้ใน environment variable ชื่อ &lt;code&gt;SOPS_AGE_KEY&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;โดยใช้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;sops --decrypt examples&#x2F;data.age-enc.yaml &amp;gt; examples&#x2F;data.yaml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แต่ปัญหาก็คือใครเป็นคนเก็บ Age Secret Key และการแจกจ่าย key ให้คนอื่นใช้โดยไม่รู้ว่าใครเป็นคนใช้งาน ถือว่าเป็นปัญหาหนึ่งของ security ในรูปเป็นตัวอย่างในการใช้ Age Encryption โดยเก็บ  Age Secret Key ไว้ใน 1password&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;100-secrets-github-actions-sops-with-azure-key-vault&#x2F;Untitled.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;blog.thenets.org&#x2F;how-to-commit-encrypted-files-to-git-with-mozilla-sops&#x2F;&quot;&gt;https:&#x2F;&#x2F;blog.thenets.org&#x2F;how-to-commit-encrypted-files-to-git-with-mozilla-sops&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;แต่ก็กลับมาประเด็นเดิมคือ การแจกจ่าย Key (Key Distribution) ให้คนอื่นใช้โดยไม่รู้ว่าใครเป็นคนใช้งาน อาจจะเกิดปัญหาเรื่อง Key หลุดแล้ว Track ไม่ได้ว่าเกิดอะไร ดังนั้นการใช้ 3rd Party Secret Management ช่วย ก็จะเป็นทางออกที่ดี ในที่นี้ผมจะใช้ Azure Key Vault เพราะแทนที่เราจะเก็บตัว Private Key นั้นเอง เราให้ Azure Key Vault ช่วยเก็บให้ และการเอาออกมาใช้ ด้วยสิทธิ์ของ User ที่อยู่ใน Azure แทน แบบนี้เราก็สามารถ track ได้ว่า user ที่มีสิทธิ์เท่านั้นนะ สามารถเข้าถึง key ได้ รวมถึงมีประวัติการใช้งาน key อีกด้วย&lt;&#x2F;p&gt;
&lt;h1 id=&quot;3-kaaraich-sops-dwy-azure-key-vault&quot;&gt;3. การใช้ SOPS ด้วย Azure Key Vault&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-kaaraich-sops-dwy-azure-key-vault&quot; aria-label=&quot;Anchor link for: 3-kaaraich-sops-dwy-azure-key-vault&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;ในการใช้ SOPS ด้วย Azure Key Vault ดูประกอบดังนี้&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;100-secrets-github-actions-sops-with-azure-key-vault&#x2F;DevOps_-_Secrets_Management.jpg&quot; alt=&quot;DevOps - Secrets Management.jpg&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;โดยเริ่มต้นสร้าง Azure Key Vault ก่อน และสร้าง Key สำหรับ SOPS แล้วก็สร้าง Service Principle สำหรับใช้ใน GitHub Actions&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;az&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; login&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; ตั้งค่า default subscription&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;az&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; account set&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;subscription&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Your subscription Name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; สร้าง Resource Group ถ้ายังไม่มี&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;az&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; group create&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;name&lt;&#x2F;span&gt; rg-common&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;location&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Central US&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Create a Vault, a key, and give the service principal access:&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;az&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; keyvault create&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;name&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;kv-github-action&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;resource-group&lt;&#x2F;span&gt; rg-common&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;location&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Central US&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;az&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; keyvault key create&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;name&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;sops-key&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;vault-name&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;kv-github-action&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;protection&lt;&#x2F;span&gt; software&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;ops&lt;&#x2F;span&gt; encrypt decrypt&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นสร้าง Service Principle สำหรับ Key Vault เพื่อให้มีสิทธิ์เท่าที่จำเป็น (Principle of least privilege)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;az&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ad sp create-for-rbac&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Display Name of Service Principle&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;role&lt;&#x2F;span&gt; Contributor&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;scopes&lt;&#x2F;span&gt; &#x2F;subscriptions&#x2F;&lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;Subscription ID&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt;&#x2F;resourceGroups&#x2F;&lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;resource_Group_name&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt;&#x2F;providers&#x2F;Microsoft.KeyVault&#x2F;vaults&#x2F;&lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;vault_name&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เรื่อง Role Contributor อาจจะมีสิทธิสูงเกินไป อาจจะเลือก Role อื่นตามความเหมาะสม โดยผลลัพธ์จะออกมาหน้าตาประมาณนี้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-braces z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;appId&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&amp;lt;some-uuid&amp;gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;displayName&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;my-keyvault-sp&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;http:&#x2F;&#x2F;my-keyvault-sp&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;password&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&amp;lt;some-uuid&amp;gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;tenant&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&amp;lt;tenant-id&amp;gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-braces z-end z-shell&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นตั้งค่า Environment Variable โดยเอา Value จากข้างบน และให้สิทธิ์ Key Vault ให้กับ Service Principle&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-shell&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;AZURE_CLIENT_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;appId&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-shell&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;AZURE_TENANT_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;tenant&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-shell&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;AZURE_CLIENT_SECRET&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;password&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;az&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; keyvault set-policy&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;name&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;kv-github-action&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;resource-group&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;rg-common&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;spn&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;AZURE_CLIENT_ID&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;key-permissions&lt;&#x2F;span&gt; encrypt decrypt&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;ต่อไปเราจะอ่าน Azure Key Vault ID มา จะเป็นหน้าตามประมาณนี้ &lt;code&gt;[https:&#x2F;&#x2F;sops.vault.azure.net&#x2F;keys&#x2F;sops-key&#x2F;some-string](https:&#x2F;&#x2F;sops.vault.azure.net&#x2F;keys&#x2F;sops-key&#x2F;some-string)&lt;&#x2F;code&gt; และใช้ในการ Encrypt SOPS&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Read the key id:&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;az&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; keyvault key show&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;name&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;sops-key&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;vault-name&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;kv-github-action&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;query&lt;&#x2F;span&gt; key.kid&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Encrypt&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sops&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;encrypt&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;azure-kv&lt;&#x2F;span&gt; https:&#x2F;&#x2F;sops.vault.azure.net&#x2F;keys&#x2F;sops-key&#x2F;some-string examples&#x2F;data.yaml &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; examples&#x2F;data.azure-enc.yaml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;โดยจะมีหน้าตาประมาณนี้&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;100-secrets-github-actions-sops-with-azure-key-vault&#x2F;Screen_Shot_2565-04-14_at_16.12.50.png&quot; alt=&quot;Screen Shot 2565-04-14 at 16.12.50.png&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Upload Service Principle ไปที่ GitHub Secrets&lt;&#x2F;li&gt;
&lt;li&gt;จากนั้น Commit ไฟล์ที่ผ่านการ Encrypt แล้ว เช่น &lt;code&gt;examples&#x2F;data.azure-enc.yaml&lt;&#x2F;code&gt; ไปยัง Private Git Repo&lt;&#x2F;li&gt;
&lt;li&gt;ตั้งค่าให้ GitHub Actions สามารถที่จะ Decrypt secret ที่เราต้องการออกมาได้ จาก Path ที่อยู่ใน yaml file&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ตัวอย่างการใช้งาน&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;steps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;actions&#x2F;checkout@v3&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;mildronize&#x2F;actions-get-secret-sops&#x2F;azure@v1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;sops&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;azure.enc.yaml&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Encrypted SOPS yaml path
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;property-path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;.scope_a.app_service.app1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; yq&#x2F;jq expression syntax for getting a particular value
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;decrypting-key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets.Azure_Credential }}&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Azure Service Principle
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;sops-version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;3.7.2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;echo &amp;quot;${{ steps.sops.outputs.secret }}&amp;quot;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;ในการใช้งาน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;marketplace&#x2F;actions&#x2F;get-secrets-from-encrypted-sops&quot;&gt;mildronize&#x2F;actions-get-secret-sops&lt;&#x2F;a&gt; จะต้องกำหนด &lt;code&gt;property-path&lt;&#x2F;code&gt; สำหรับเข้าถึง secret ที่เราต้องการผ่าน path ของ yaml ไฟล์ โดยใช้ syntax ของ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;stedolan.github.io&#x2F;jq&#x2F;&quot;&gt;jq&lt;&#x2F;a&gt; หรือ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mikefarah&#x2F;yq&quot;&gt;yq&lt;&#x2F;a&gt; ก็ได้&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h1 id=&quot;4-taw-yaangkaaraichngaancchring-sops-dwy-azure-key-vault-aelaekb-encrypted-secrets-bn-private-git-repo&quot;&gt;4. ตัวอย่างการใช้งานจริง SOPS ด้วย Azure Key Vault และเก็บ Encrypted Secrets บน Private Git repo&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-taw-yaangkaaraichngaancchring-sops-dwy-azure-key-vault-aelaekb-encrypted-secrets-bn-private-git-repo&quot; aria-label=&quot;Anchor link for: 4-taw-yaangkaaraichngaancchring-sops-dwy-azure-key-vault-aelaekb-encrypted-secrets-bn-private-git-repo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;โค๊ดนี้&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;deploy-multiple-azure-app-services-using-github-actions-matrix&#x2F;blob&#x2F;main&#x2F;.github&#x2F;workflows&#x2F;build-and-deploy.yml&quot;&gt;ปรับปรุงโค๊ด GitHub Actions เดิม&lt;&#x2F;a&gt; สามารถไปตามการพูดของผมเรื่อง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;deploy-multiple-azure-app-services-using-github-actions-matrix&quot;&gt;“&lt;strong&gt;&lt;strong&gt;Deploy .NET Core 6 to Multiple Azure App Services using GitHub Actions Matrix&lt;&#x2F;strong&gt;&lt;&#x2F;strong&gt;”&lt;&#x2F;a&gt; เมื่อวันที่ 7 เม.ย. 2565 ที่ผ่านมาได้&lt;&#x2F;p&gt;
&lt;p&gt;ตัวนี้จะเป็นการ Build .NET Core 6 และ Deploy ไปยัง Azure App Service จำนวน 3 servers พร้อมๆ กันโดยใช้ GitHub Actions และอ่าน Azure Service Principle จาก GitHub Secrets จากนั้น นำไปอ่านค่า SOPS Secrets จากใน Private Repo&lt;&#x2F;p&gt;
&lt;p&gt;โดยตั้งค่า GitHub Secret Name ดังนี้&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AzureKeyVault_ServicePrinciple__kv_github_action__sp_sops_github_action&lt;&#x2F;code&gt; เอาไว้เก็บ Service Principal จากหัวข้อที่ผ่านมา&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;GH_TOKEN_PAT&lt;&#x2F;code&gt; เอาไว้เก็บ Personal Access Token สำหรับ Checkout GitHub Private Repo&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;และนี่เป็นตัวอย่าง SOPS data เก็บไว้ในไฟล์ &lt;code&gt;my-sops.enc.yaml&lt;&#x2F;code&gt; ที่เอาไว้เก็บ Publish Profile ของแต่ละ App Service&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;thadaw&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;app_service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;cat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Publish Profile of Cat Server from Azure App Service&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;dog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Publish Profile of Dog Server from Azure App Service&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;ant&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Publish Profile of Ant Server from Azure App Service&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;GitHub Actions:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Build and Deploy .NET Core&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Controls when the workflow will run
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-constant z-language z-boolean z-yaml&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Allows you to run this workflow manually from the Actions tab
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;workflow_dispatch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; This env is sharing between jobs
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;dotnet_version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;6.0&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;artifact_name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;web-api&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;project_path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;src&#x2F;DemoWebAPI&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;	&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;my_private_repo_secrets_version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;0.0.1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;sops_service_principle_gh_secret_name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;AzureKeyVault_ServicePrinciple__kv_github_action__sp_sops_github_action&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;sops_secrets_path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;.&#x2F;my-sops.enc.yaml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;sops_version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;3.7.2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;runs-on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;ubuntu-latest&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;steps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Checkout Code&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;actions&#x2F;checkout@v2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Setup .NET Core&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;actions&#x2F;setup-dotnet@v1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;dotnet-version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ env.dotnet_version }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Publish folder&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-block-scalar z-literal z-yaml&quot;&gt;|&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;          cd &amp;quot;.&#x2F;${{ env.project_path }}&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;          dotnet restore
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;          dotnet build --configuration Release
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;          dotnet publish --configuration Release --output .&#x2F;output
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;&lt;&#x2F;span&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Upload artifact for deployment job&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;actions&#x2F;upload-artifact@v2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ env.artifact_name }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;${{ env.project_path }}&#x2F;output&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;retention-days&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-yaml&quot;&gt;1&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Keep artifact on remote only 1 day
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;deploy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;🚀 Deploy to ${{ matrix.id }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;runs-on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;ubuntu-latest&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;needs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;build&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;strategy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;fail-fast&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-yaml&quot;&gt;false&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;matrix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;include&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;demo_multi_app_cat&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;            &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;thadaw-demo-multi-app-cat&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;            &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;property_path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;.thadaw.app_service.cat&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;demo_multi_app_dog&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;            &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;thadaw-demo-multi-app-dog&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;            &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;property_path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;.thadaw.app_service.dog&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;demo_multi_app_ant&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;            &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;thadaw-demo-multi-app-ant&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;            &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;property_path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;.thadaw.app_service.ant&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;steps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Download artifact from build job&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;actions&#x2F;download-artifact@v2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ env.artifact_name }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Checkout My Private repo Secrets&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;actions&#x2F;checkout@v3&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;repository&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;mildronize&#x2F;my-private-repo-secrets&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;ref&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;${{ env.my_private_repo_secrets_version }}&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets.GH_TOKEN_PAT }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;.&#x2F;my-private-repo-secrets&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Get Credential from SOPS&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;mildronize&#x2F;actions-get-secret-sops&#x2F;azure@v1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;sops&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;.&#x2F;my-private-repo-secrets&#x2F;${{ env.sops_secrets_path }}&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;property-path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;${{ matrix.property_path }}&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;decrypting-key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets[env.sops_service_principle_gh_secret_name] }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;sops-version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;${{ env.sops_version }}&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Deploy to Azure Web App&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;deploy-to-webapp&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;azure&#x2F;webapps-deploy@v2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;app-name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ matrix.name }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;publish-profile&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ steps.sops.outputs.secret }}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;package&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-decimal z-yaml&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ก็จบกันไปแล้วนะคับ ใครมีประเด็นเรื่องใดอยากจะนำเสนอ สามารถพูดคุยกันได้เสมอครับ&lt;&#x2F;p&gt;
&lt;p&gt;ขอบคุณที่อ่านจนจบ แล้วพบกันใหม่&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>การใช้งาน Multi-Modules ต่อ Workspace ใน VS Codeและ วิธีการแก้ปัญหา You are outside of a module and outside of $GOPATH&#x2F;src</title>
		<published>2022-03-19T00:00:00+00:00</published>
		<updated>2022-03-19T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/you-are-outside-of-a-module-and-outside-of-dollargopathsrc/" type="text/html"/>
		<id>https://thadaw.com/posts/you-are-outside-of-a-module-and-outside-of-dollargopathsrc/</id>
		<content type="html">&lt;p&gt;จากที่ลองทำตาม Tutorial ในการ import Go Module ใน Official Docs&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;go.dev&#x2F;doc&#x2F;tutorial&#x2F;create-module&quot;&gt;Create a module&lt;&#x2F;a&gt; -- Write a small module with functions you can call from another module.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;go.dev&#x2F;doc&#x2F;tutorial&#x2F;call-module-code.html&quot;&gt;Call your code from another module&lt;&#x2F;a&gt; -- Import and use your new module.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;มี Project Structure&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── greetings
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│   ├── go.mod
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│   └── greetings.go
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;└── hello
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    ├── go.mod
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    └── hello.go
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้น Vs Code ก็แจ้ง Error ว่า &quot;Error loading workspace: You are outside of a module and outside of $GOPATH&#x2F;src.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;you-are-outside-of-a-module-and-outside-of-dollargopathsrc&#x2F;error-sample.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution&quot; aria-label=&quot;Anchor link for: solution&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จากที่ไปอ่านมา ตัว &lt;code&gt;gopls&lt;&#x2F;code&gt; ซึ่งเป็น libs ที่ช่วยในพวก Editor ต่างๆ พบว่า &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;tools&#x2F;blob&#x2F;master&#x2F;gopls&#x2F;doc&#x2F;workspace.md#one-module&quot;&gt;ถ้าเป็น Go 1.17 ลงไปจะสามารถเปิดได้แค่ 1 module&#x2F;workspace&lt;&#x2F;a&gt; เท่านั้น&lt;&#x2F;p&gt;
&lt;p&gt;พอลองเปิดแยก Module ก็พบว่าจริงไม่ Error แล้ว
&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;you-are-outside-of-a-module-and-outside-of-dollargopathsrc&#x2F;one-module-go.1.17.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าเราจะ&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;tools&#x2F;blob&#x2F;master&#x2F;gopls&#x2F;doc&#x2F;workspace.md#multiple-modules&quot;&gt;ใช้งานหลาย Modules พร้อมกันใน 1 Workspace เราควรใช้ Go 1.18&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;พออัพเกรดไป go 1.18 ก็ใช้งานได้แล้ว&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;you-are-outside-of-a-module-and-outside-of-dollargopathsrc&#x2F;multiple-modules.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ref&quot;&gt;Ref:&lt;a class=&quot;zola-anchor&quot; href=&quot;#ref&quot; aria-label=&quot;Anchor link for: ref&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;issues&#x2F;45015#issuecomment-802556434&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธีการตั้งค่า SSH สำหรับ GitHub เพื่อให้จำรหัสผ่านบน Windows, WSL, MacOS และ Ubuntu</title>
		<published>2021-12-08T00:00:00+00:00</published>
		<updated>2021-12-08T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/how-setup-ssh-for-git-on-windows-wsl-mac-ubuntu/" type="text/html"/>
		<id>https://thadaw.com/posts/how-setup-ssh-for-git-on-windows-wsl-mac-ubuntu/</id>
		<content type="html">&lt;p&gt;ถ้าใครจะตั้งค่า SSH สำหรับ Remote Server อื่นๆ ก็ใช้หลักการเดียวกันได้ เพียงแต่ในบทความนี้ยกตัวอย่าง GitHub&lt;&#x2F;p&gt;
&lt;p&gt;บทความนี้จะแบ่งจะเป็น 2 ส่วนใหญ่ๆ คือฝั่ง Unix-based (Mac OS, Ubuntu, WSL) และฝั่ง Windows ครับ ก่อนจะเข้าเรื่อง ผมขออธิบายหลักการของ SSH เบื้องต้นนะครับ การเชื่อมต่อผ่าน SSH หรือ Secure Shell นั้น คือการเชื่อมต่อไปเครื่องต้นทาง (Local) ไปยังเครื่องปลายทาง (Remote) ผ่านการเข้ารหัส ซึ่งมั่นใจได้ว่าการเชื่อมต่อนั้นปลอดภัยในระดับที่ยอมรับได้ในระดับสากล&lt;&#x2F;p&gt;
&lt;p&gt;ในการเชื่อมต่อนั้นจะเป็นแบบ Asymmetric Encryption หรือ การเข้ารหัสแบบไม่สมมาตร
โดยก่อนจะมีการส่งข้อมูลจะมีการสร้างคู่ของกุญแจ ที่ก็ต้องใช้ร่วมกันเท่านั้น เราจะเรียกว่า Public key และ Private key ซึ่งวิธีเข้ารหัสที่ได้รับนิยมคือ RSA&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Public key คือ กุญแจสาธารณะ ซึ่งคือสามารถเผยแพร่ให้ เครื่องปลายทางได้&lt;&#x2F;li&gt;
&lt;li&gt;Private key คือ กุญแจส่วนตัว ซึ่งไม่ควรเผยแพร่ และเจ้าของข้อมูลควรจะถือไว้เท่านั้น&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;โดยก่อนที่จะมีการส่งข้อมูลจะมีการเข้ารหัสด้วย Public Key ทุกครั้ง และเมื่อข้อมูลถูกส่งมายั่งเครื่องต้นทางที่มี Private key แล้วก็จะสามารถถอดรหัสเพื่อเห็นข้อมูลจริงๆ ได้&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;how-setup-ssh-for-git-on-windows-wsl-mac-ubuntu&#x2F;Asymmetric-Encryption.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;สามารถอ่านเพิ่มได้ที่ &lt;a rel=&quot;nofollow noreferrer&quot; title=&quot;4 Cryptography Concept ที่ Developer ทุกคนควรรู้&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;scb-techx&#x2F;4-cryptography-concept-%E0%B8%97%E0%B8%B5%E0%B9%88-developer-%E0%B8%97%E0%B8%B8%E0%B8%81%E0%B8%84%E0%B8%99%E0%B8%84%E0%B8%A7%E0%B8%A3%E0%B8%A3%E0%B8%B9%E0%B9%89-15a806b6771d&quot;&gt;4 Cryptography Concept ที่ Developer ทุกคนควรรู้&lt;&#x2F;a&gt; โดยคุณ Kittitorn Kanokwalai&lt;&#x2F;p&gt;
&lt;p&gt;ก่อนที่เข้าเรื่องในบทความนี้จะเป็นวิธีการใช้ OpenSSH ที่ใช้อยากแพร่หลายใน Linux และ Mac มาอย่างยาวนาน และแนะนำวิธีการตั้งค่า OpenSSH บน Windows (แทนที่จะเป็น Putty) โดยการใช้งาน OpenSSH จะมี &lt;code&gt;ssh-agent&lt;&#x2F;code&gt; ที่เป็น service ที่ทำงานหลังบ้าน เพื่อให้เราสามารถนำ key ของเราไปเชื่อมต่อกับ server ปลายทางได้&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1-mac-os-ubuntu-wsl&quot;&gt;1. Mac OS, Ubuntu, WSL&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-mac-os-ubuntu-wsl&quot; aria-label=&quot;Anchor link for: 1-mac-os-ubuntu-wsl&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1-1-withiikaarsraang-ssh-keys-aelakaaraichngaan&quot;&gt;1.1 วิธีการสร้าง SSH Keys และการใช้งาน&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-1-withiikaarsraang-ssh-keys-aelakaaraichngaan&quot; aria-label=&quot;Anchor link for: 1-1-withiikaarsraang-ssh-keys-aelakaaraichngaan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;สร้าง SSH key&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ssh-keygen&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;t&lt;&#x2F;span&gt; rsa&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;b&lt;&#x2F;span&gt; 4096&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;C&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;your_email@example.com&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;.ssh&#x2F;id_rsa&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: ถ้าเป็น Windows ต้องใส่ &lt;code&gt;-f ~&#x2F;.ssh&#x2F;id_rsa&lt;&#x2F;code&gt; ไม่งั้นจะ error ว่า &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;newbedev.com&#x2F;ssh-keygen-no-such-file-or-directory&quot;&gt;SSH-Keygen &quot;no such file or directory&quot;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Copy ข้อมูลในไฟล์ &lt;code&gt;~&#x2F;.ssh&#x2F;id_rsa.pub&lt;&#x2F;code&gt; (ซึ่งก็คือ Public Key) ไปวางที่ GitHub account settings (https:&#x2F;&#x2F;github.com&#x2F;settings&#x2F;keys).&lt;&#x2F;p&gt;
&lt;p&gt;ติดตั้ง SSH Agent&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-eval z-shell&quot;&gt;eval&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-command z-parens z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ssh-agent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Add ตัว private key&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ssh-add ~&#x2F;.ssh&#x2F;id_rsa
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ลองทดสอบ SSH key:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ssh&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;T&lt;&#x2F;span&gt; git@github.com&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Hi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;Your Username&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt;! You&lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;ve successfully authenticated, but GitHub does not provide shell access.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ไปยังโฟลเดอร์ที่ของ Git Repo ในเครื่องเราแล้วเปลี่ยน Git remote ให้เป็นแบบ SSH&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git remote set-url origin git@github.com:username&#x2F;your-repository.git&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นลอง commit และ push ดู ระบบไม่ควรถามหารหัสผ่านแล้ว&lt;&#x2F;p&gt;
&lt;p&gt;Ref: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;developius&#x2F;c81f021eb5c5916013dc&quot;&gt;Finnian Anderson&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;github-ae@latest&#x2F;authentication&#x2F;connecting-to-github-with-ssh&#x2F;generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent&quot;&gt;GitHub Official Doc&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-windows-10-11&quot;&gt;2. Windows 10, 11&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-windows-10-11&quot; aria-label=&quot;Anchor link for: 2-windows-10-11&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เมื่อปี 2018 ผมได้เขียนบทความ &lt;a href=&quot;&#x2F;s&#x2F;mo4feik&#x2F;&quot;&gt;วิธีตั้งค่าการใช้งาน Github (แบบไม่ต้องกรอกรหัสผ่านทุกครั้ง) ผ่าน SSH บน Windows&lt;&#x2F;a&gt; ซึ่งได้แนะนำวิธีการใช้ Putty สำหรับทำงานเป็นเบื้องหลัง แต่เราจำเป็นต้องเปิดตัว agent ขึ้นมาทุกครั้ง หรือถ้าไม่อย่างนั้นก็ต้อง ตั้งค่า startup เอง&lt;&#x2F;p&gt;
&lt;p&gt;เมื่อปี 2019 Windows ได้ปล่อยความสามารถอย่างหนึ่งคือ OpenSSH Client ที่เป็น service อยู่บน Windows ซึ่งดีมากๆ เลย ที่เราไม่ต้องพึ่งโปรแกรมอื่นๆ อย่างเช่น Putty&lt;&#x2F;p&gt;
&lt;p&gt;ในหัวข้อนี้จะเน้นที่ Powershell เท่านั้นนะครับ ถ้าใครใช้ WSL หรือ Git Bash บน Windows แล้วแนะนำให้ใช้หัวข้อข้างบนแทน&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-1-etriiym-ssh-samhrab-windows-10&quot;&gt;2.1 เตรียม SSH สำหรับ Windows 10&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-1-etriiym-ssh-samhrab-windows-10&quot; aria-label=&quot;Anchor link for: 2-1-etriiym-ssh-samhrab-windows-10&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;OpenSSH ได้ถูกปล่อยออกมาเป็นส่วนหนึ่งของ Windows 10 ทำให้เราสามารถใช้คำสั่ง SSH ผ่าน cmd หรือ powershell ได้ เพื่อให้สามารถใช้งาน OpenSSH ได้เราจำเป็นจะต้องติดตั้ง OpenSSH และสั่งให้ service &lt;code&gt;ssh-agent&lt;&#x2F;code&gt; ทำงานเบื้องหลังไว้&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;เปิด &lt;code&gt;Manage optional features&lt;&#x2F;code&gt; จาก start menu แล้วติดตั้ง &lt;code&gt;OpenSSH Client&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เปิด Powershell แบบ Admin&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;powershell&quot; class=&quot;language-powershell z-code&quot;&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-support z-function z-powershell&quot;&gt;Get-Service&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;Name ssh&lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;agent &lt;span class=&quot;z-keyword z-operator z-other z-powershell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-powershell&quot;&gt;Set-Service&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;StartupType Automatic
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-support z-function z-powershell&quot;&gt;Get-Service&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;Name ssh&lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;agent &lt;span class=&quot;z-keyword z-operator z-other z-powershell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-powershell&quot;&gt;Set-Service&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;Status Running
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แนะนำให้อ่าน&lt;a rel=&quot;nofollow noreferrer&quot; title=&quot;Official Docs&quot; href=&quot;https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;windows-server&#x2F;administration&#x2F;openssh&#x2F;openssh_keymanagement&quot;&gt;บทความการตั้งค่า OpenSSH ของ Microsoft&lt;&#x2F;a&gt; เพิ่มเติม&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าใครไม่ถนัดการใช้ผ่าน command-line สามารถดูการตั้งค่าแบบ UI ได้ที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;newbedev.com&#x2F;how-to-run-ssh-add-on-windows&quot;&gt;newbedev.com&lt;&#x2F;a&gt; หรือ &lt;a rel=&quot;nofollow noreferrer&quot; title=&quot;SSH keys on Windows 10&quot; href=&quot;https:&#x2F;&#x2F;richardballard.co.uk&#x2F;ssh-keys-on-windows-10&#x2F;&quot;&gt;SSH keys on Windows 10&lt;&#x2F;a&gt; โดย Richard Ballard&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-2-withiikaarsraang-ssh-keys-aelakaaraichngaan-bn-powershell&quot;&gt;2.2 วิธีการสร้าง SSH Keys และการใช้งาน บน PowerShell&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-2-withiikaarsraang-ssh-keys-aelakaaraichngaan-bn-powershell&quot; aria-label=&quot;Anchor link for: 2-2-withiikaarsraang-ssh-keys-aelakaaraichngaan-bn-powershell&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;สามารถใช้วิธีการเดียวกันจาก Mac OS, Ubuntu, WSL ได้เลย ที่เขียนไว้แล้วข้างบน&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3-withiikaarthiitham-ssh-agent-ccham-key-passphrase&quot;&gt;3. วิธีการที่ทำ SSH Agent จำ Key passphrase&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-withiikaarthiitham-ssh-agent-ccham-key-passphrase&quot; aria-label=&quot;Anchor link for: 3-withiikaarthiitham-ssh-agent-ccham-key-passphrase&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เราสามารถใช้งานทั้ง Mac OS, Ubuntu, WSL และ Windows เลย โดยมี 2 วิธี  ขอบคุณ &lt;a rel=&quot;nofollow noreferrer&quot; title=&quot;How to make Powershell remember the SSH key passphrase.&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;danieldogeanu&#x2F;16c61e9b80345c5837b9e5045a701c99&quot;&gt;Daniel Dogeanu&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-1-aich-command-ssh-add&quot;&gt;3.1 ใช้ Command ssh-add&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-1-aich-command-ssh-add&quot; aria-label=&quot;Anchor link for: 3-1-aich-command-ssh-add&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;Add your SSH key to the &lt;code&gt;ssh-agent&lt;&#x2F;code&gt; by issuing the &lt;code&gt;ssh-add&lt;&#x2F;code&gt; command and entering your passphrase:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ssh-add $HOME&#x2F;.ssh&#x2F;your_file_name
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;ถ้าใครจะใช้ SSH Key มากกว่าหนึ่ง แนะนำให้ใช้วิธีการที่ 2 ซึ่งเราสามารถ setup ชื่อของ Host ที่แตกต่างกันได้ เมื่อเราใช้คนละ account กัน แนะนำให้ดูเพิ่มใน หัวข้อที่ 4. การใช้งานหลาย Key ในเครื่องเดียวกัน&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;3-2-tangkhaaaiflain-ssh-config&quot;&gt;3.2 ตั้งค่าไฟล์ใน &lt;code&gt;~&#x2F;.ssh&#x2F;config&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-2-tangkhaaaiflain-ssh-config&quot; aria-label=&quot;Anchor link for: 3-2-tangkhaaaiflain-ssh-config&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;ตั้งค่าให้ SSH สามารถที่จะเพิ่ม key ลงไปใน agent โดยการแก้ไขไฟล์ config ที่อยู่ใน &lt;code&gt;$HOME\.ssh\config&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Host *
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  AddKeysToAgent yes
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  IdentitiesOnly yes
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;โดยที่เราสามารถใส่ config ของ SSH key ที่เราสร้างขึ้นมาได้ หรือจะสามารถใส่หลาย key ได้ด้วย&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Host github.com
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  HostName github.com
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  User your_user_name
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  IdentityFile ~&#x2F;.ssh&#x2F;your_file_name
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;เรียบร้อยแล้ว ถ้ายังใช้งานไม่ได้ให้ restart shell&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;4-kaaraichngaanhlaay-key-ainekhruue-ngediiywkan&quot;&gt;4. การใช้งานหลาย Key ในเครื่องเดียวกัน&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-kaaraichngaanhlaay-key-ainekhruue-ngediiywkan&quot; aria-label=&quot;Anchor link for: 4-kaaraichngaanhlaay-key-ainekhruue-ngediiywkan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เราสามารถใช้งานทั้ง Mac OS, Ubuntu, WSL และ Windows เลย
โดยการเข้าไปแก้ไขไฟล์ &lt;code&gt;~&#x2F;.ssh&#x2F;config&lt;&#x2F;code&gt; และเพิ่มหัวข้อ Host ใหม่ โดยในทีนี้ผมเลือกให้ &lt;code&gt;Host github.com&lt;&#x2F;code&gt; เป็นค่าเริ่มต้นของ account github ส่วนตัว และใช้ &lt;code&gt;Host work.github.com&lt;&#x2F;code&gt; เป็น host สำหรับ account github ที่ทำงาน&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Host *
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	AddKeysToAgent yes
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	IdentitiesOnly yes
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Host github.com
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	HostName github.com
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	User personal-user
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	IdentityFile ~&#x2F;.ssh&#x2F;personal_rsa
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Host work.github.com
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	HostName github.com
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	User work-user
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	IdentityFile ~&#x2F;.ssh&#x2F;work_rsa
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ลองตรวจสอบดูว่า key ของเราถูกติดตั้งหรือยัง?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ssh-add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;4096&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; SHA256:XXXXXXXXXXXXXX personal@email.com (RSA&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;4096&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; SHA256:XXXXXXXXXXXXXX work@email.com (RSA&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ตัวอย่างวิธีการใช้ เราสามารถใช้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;# สำหรับเปลี่ยน Remote location ของบัญชีส่วนตัว&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; remote set-url origin git@work.github.com:your-username&#x2F;your-repo.git&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;# สำหรับเปลี่ยน Clone ของบัญชีส่วนตัว&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; clone git@work.github.com:your-username&#x2F;your-repo.git&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;ซึ่งตรงนี้จะเหมือนกับหน้าเว็บ GitHub แนะนำเลย&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;แต่ถ้าเราจะใช้ &lt;code&gt;Host work.github.com&lt;&#x2F;code&gt; เป็น host สำหรับ account github ที่ทำงาน เพียงแค่เปลี่ยน host ใน URL เท่านั้นเอง&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;# สำหรับเปลี่ยน Remote location ของบัญชีที่ทำงาน&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; remote set-url origin git@github.com:your-username&#x2F;your-repo.git&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;# สำหรับเปลี่ยน Remote location ของบัญชีที่ทำงาน&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; clone origin git@github.com:your-username&#x2F;your-repo.git&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;5-withiikaaraekpayhaa&quot;&gt;5. วิธีการแก้ปัญหา&lt;a class=&quot;zola-anchor&quot; href=&quot;#5-withiikaaraekpayhaa&quot; aria-label=&quot;Anchor link for: 5-withiikaaraekpayhaa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;ถ้าเป็นแบบนี้ แสดงว่า SSH Agent ยังไม่ได้ทำงาน background ให้ใช้ คำสั่ง &lt;code&gt;eval &quot;$(ssh-agent -s)&quot;&lt;&#x2F;code&gt; เพื่อ Start Agent ขึ้นมา (เฉพาะ Mac, Linux, WSL)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ssh-add&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Could&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; not open a connection to your authentication agent.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;ถ้าเป็นแบบนี้ แสดงว่า SSH Agent ทำงานแล้ว แต่ยังไม่ได้ติดตั้ง key ของเราเลย อาจจะต้องใช้คำสั่ง &lt;code&gt;ssh-add &#x2F;path&#x2F;key&lt;&#x2F;code&gt; ไปก่อน เพื่อเพิ่ม key เข้าไป&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ssh-add&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;The&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; agent has no identities.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;ถ้ายังไม่ได้ลองดู Verbose ของ SSH ดู&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ssh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;vv&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;T&lt;&#x2F;span&gt; git@work.github.com&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถ้าลองทำแล้วได้ไม่ได้ยังไง มาแบ่งปันกันได้นะครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;withiiaichngaanrwmkab-sourcetree&quot;&gt;วิธีใช้งานร่วมกับ SourceTree&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiiaichngaanrwmkab-sourcetree&quot; aria-label=&quot;Anchor link for: withiiaichngaanrwmkab-sourcetree&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;how-setup-ssh-for-git-on-windows-wsl-mac-ubuntu&#x2F;openssh-sourcetree.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;เราจำเป็นต้องใช้ &lt;strong&gt;SourceTree แบบ Admin&lt;&#x2F;strong&gt; ถ้าสังเกตุในหัวข้อ 2.1 เตรียม SSH สำหรับ Windows 10 มีการสั่งให้ service &lt;code&gt;ssh-agent&lt;&#x2F;code&gt; เริ่มทำงาน จำเป็นต้องใช้สิทธิ Admin ไปด้วยในการใช้งานบน SourceTree มิเช่นนั้นมันจะ Error &quot;ssh-agent failed with code-1 system.componentmodel.win32exception access is denied&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Sourcetree สามารถอ่านไฟล์ &lt;code&gt;~&#x2F;.ssh&#x2F;config&lt;&#x2F;code&gt; ได้ ดังนั้น custom hostname เราจะสามารถใช้งานได้&lt;&#x2F;p&gt;
&lt;p&gt;ให้เราอัพเดท Remote ไปที่&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;git@work.github.com:your-username&#x2F;your-repo.git
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;aanephimetim&quot;&gt;อ่านเพิ่มเติม&lt;a class=&quot;zola-anchor&quot; href=&quot;#aanephimetim&quot; aria-label=&quot;Anchor link for: aanephimetim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; title=&quot;4 Cryptography Concept ที่ Developer ทุกคนควรรู้&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;scb-techx&#x2F;4-cryptography-concept-%E0%B8%97%E0%B8%B5%E0%B9%88-developer-%E0%B8%97%E0%B8%B8%E0%B8%81%E0%B8%84%E0%B8%99%E0%B8%84%E0%B8%A7%E0%B8%A3%E0%B8%A3%E0%B8%B9%E0%B9%89-15a806b6771d&quot;&gt;4 Cryptography Concept ที่ Developer ทุกคนควรรู้&lt;&#x2F;a&gt; โดยคุณ Kittitorn Kanokwalai&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; title=&quot;SSH keys on Windows 10&quot; href=&quot;https:&#x2F;&#x2F;richardballard.co.uk&#x2F;ssh-keys-on-windows-10&#x2F;&quot;&gt;SSH keys on Windows 10&lt;&#x2F;a&gt; - Richard Ballard&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; title=&quot;Official Docs&quot; href=&quot;https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;windows-server&#x2F;administration&#x2F;openssh&#x2F;openssh_keymanagement&quot;&gt;OpenSSH key management&lt;&#x2F;a&gt; by Microsoft&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;linuxize.com&#x2F;post&#x2F;using-the-ssh-config-file&#x2F;&quot;&gt;วิธีการใช้งาน ~&#x2F;.ssh&#x2F;config เพิ่มเติม&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.ssh.com&#x2F;academy&#x2F;ssh&#x2F;agent&quot;&gt;Understand Basic SSH Agent&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;enterprise-server@3.4&#x2F;developers&#x2F;overview&#x2F;using-ssh-agent-forwarding&quot;&gt;Using SSH agent forwarding&lt;&#x2F;a&gt; - GitHub Official Doc&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;aang-ing&quot;&gt;อ้างอิง&lt;a class=&quot;zola-anchor&quot; href=&quot;#aang-ing&quot; aria-label=&quot;Anchor link for: aang-ing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;newbedev.com&#x2F;how-to-run-ssh-add-on-windows&quot;&gt;How to run ssh-add on windows?&lt;&#x2F;a&gt; - Newbedev.com&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; title=&quot;How to make Powershell remember the SSH key passphrase.&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;danieldogeanu&#x2F;16c61e9b80345c5837b9e5045a701c99&quot;&gt;How to make Powershell remember the SSH key passphrase.&lt;&#x2F;a&gt; - Daniel Dogeanu&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;newbedev.com&#x2F;ssh-keygen-no-such-file-or-directory&quot;&gt;SSH-Keygen &quot;no such file or directory&quot; &lt;&#x2F;a&gt; - Newbedev.com&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;developius&#x2F;c81f021eb5c5916013dc&quot;&gt;Setup SSH keys for use with GitHub&#x2F;GitLab&#x2F;BitBucket etc &lt;&#x2F;a&gt; - Finnian Anderson&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ชีวิตดีเมื่อใช้ FluentAssertions ช่วยในเขียน test เพื่อเปรียบเทียบ Object ที่ซับซ้อน</title>
		<published>2021-11-27T00:00:00+00:00</published>
		<updated>2021-11-27T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/compare-complex-object-with-fluent-assertion/" type="text/html"/>
		<id>https://thadaw.com/posts/compare-complex-object-with-fluent-assertion/</id>
		<content type="html">&lt;p&gt;สมมติว่าเรามี Data Structure ดังนี้ คำถามคือเราจะ Assert อย่างไร&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;cs&quot; class=&quot;language-cs z-code&quot;&gt;&lt;code class=&quot;language-cs&quot; data-lang=&quot;cs&quot;&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-access z-cs&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-class z-cs&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-cs&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-class z-cs&quot;&gt;Todo&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-cs&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;    &lt;span class=&quot;z-storage z-modifier z-access z-cs&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-cs&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-property z-cs&quot;&gt;&lt;span class=&quot;z-variable z-other z-member z-cs&quot;&gt;ID&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-property z-cs&quot;&gt;  &lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-property z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt; &lt;span class=&quot;z-meta z-method z-cs&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-accessor z-get z-cs&quot;&gt;get&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-cs&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-method z-cs&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-accessor z-set z-cs&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-cs&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-property z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-property z-cs&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-access z-cs&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-cs&quot;&gt;string&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-property z-cs&quot;&gt;&lt;span class=&quot;z-variable z-other z-member z-cs&quot;&gt;Title&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-property z-cs&quot;&gt;  &lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-property z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt; &lt;span class=&quot;z-meta z-method z-cs&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-accessor z-get z-cs&quot;&gt;get&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-cs&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-method z-cs&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-accessor z-set z-cs&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-cs&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-property z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-property z-cs&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-access z-cs&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-cs&quot;&gt;bool&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-property z-cs&quot;&gt;&lt;span class=&quot;z-variable z-other z-member z-cs&quot;&gt;Completed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-property z-cs&quot;&gt;  &lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-property z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt; &lt;span class=&quot;z-meta z-method z-cs&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-accessor z-get z-cs&quot;&gt;get&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-cs&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-method z-cs&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-accessor z-set z-cs&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-cs&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-property z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-property z-cs&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-access z-cs&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-class z-cs&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-cs&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-class z-cs&quot;&gt;TodoList&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-cs&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;    &lt;span class=&quot;z-storage z-modifier z-access z-cs&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-cs&quot;&gt;IEnumerable&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-cs&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic z-cs&quot;&gt;&lt;span class=&quot;z-support z-type z-cs&quot;&gt;Todo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-cs&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-method z-cs&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-cs&quot;&gt;GetTodoList&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method z-parameters z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-cs&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method z-parameters z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-cs&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-cs&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-flow z-return z-cs&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-cs&quot;&gt;new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-brackets z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-cs&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-cs&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;        &lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;            &lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-cs&quot;&gt;new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-support z-type z-cs&quot;&gt;Todo&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;ID&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-cs&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;Title&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Shopping&lt;span class=&quot;z-punctuation z-definition z-string z-end z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;Completed&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-cs&quot;&gt;false&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;            &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;            &lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-cs&quot;&gt;new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-support z-type z-cs&quot;&gt;Todo&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;ID&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-cs&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;Title&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Running&lt;span class=&quot;z-punctuation z-definition z-string z-end z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;Completed&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-cs&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;            &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;            &lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-cs&quot;&gt;new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-support z-type z-cs&quot;&gt;Todo&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;ID&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-cs&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;Title&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Reading a book&lt;span class=&quot;z-punctuation z-definition z-string z-end z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;Completed&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-cs&quot;&gt;false&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;            &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;        &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-cs&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-block z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถ้าใช้ xUnit อย่างเดียว อาจจะยุ่งยาก ลองใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.nuget.org&#x2F;packages&#x2F;FluentAssertions&quot;&gt;FluentAssertions&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;a class=&quot;zola-anchor&quot; href=&quot;#getting-started&quot; aria-label=&quot;Anchor link for: getting-started&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;ติดตั้ง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.nuget.org&#x2F;packages&#x2F;FluentAssertions&quot;&gt;FluentAssertions&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dotnet&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; add package FluentAssertions&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;version&lt;&#x2F;span&gt; 5.10.3&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เรียก &lt;code&gt;using FluentAssertions;&lt;&#x2F;code&gt; แล้วเราสามารถใช้งาน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.nuget.org&#x2F;packages&#x2F;FluentAssertions&quot;&gt;FluentAssertions&lt;&#x2F;a&gt; ได้เลย&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;cs&quot; class=&quot;language-cs z-code&quot;&gt;&lt;code class=&quot;language-cs&quot; data-lang=&quot;cs&quot;&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-cs&quot;&gt;using&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-cs&quot;&gt;Xunit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-cs&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-cs&quot;&gt;using&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-cs&quot;&gt;FluentAssertions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-cs&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-access z-cs&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-class z-cs&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-cs&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-class z-cs&quot;&gt;TodoListTest&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-cs&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;    &lt;span class=&quot;z-meta z-annotation z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-begin z-cs&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-annotation z-cs&quot;&gt;Fact&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-end z-cs&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;    &lt;span class=&quot;z-storage z-modifier z-access z-cs&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-cs&quot;&gt;void&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-method z-cs&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-cs&quot;&gt;GetTodoListTest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method z-parameters z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-cs&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method z-parameters z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-cs&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-cs&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;        &lt;span class=&quot;z-storage z-type z-variable z-cs&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;todoList&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-variable z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-cs&quot;&gt;new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-support z-type z-cs&quot;&gt;TodoList&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-cs&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-cs&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-cs&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;        &lt;span class=&quot;z-storage z-type z-variable z-cs&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;expected&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-variable z-cs&quot;&gt;=&lt;&#x2F;span&gt;  &lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-cs&quot;&gt;new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-brackets z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-cs&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-cs&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;        &lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;            &lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-cs&quot;&gt;new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-support z-type z-cs&quot;&gt;Todo&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;ID&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-cs&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;Title&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Shopping&lt;span class=&quot;z-punctuation z-definition z-string z-end z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;Completed&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-cs&quot;&gt;false&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;            &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;            &lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-cs&quot;&gt;new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-support z-type z-cs&quot;&gt;Todo&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;ID&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-cs&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;Title&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Running&lt;span class=&quot;z-punctuation z-definition z-string z-end z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;Completed&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-cs&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;            &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;            &lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-cs&quot;&gt;new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-support z-type z-cs&quot;&gt;Todo&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;ID&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-cs&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;Title&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Reading a book&lt;span class=&quot;z-punctuation z-definition z-string z-end z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-array-element z-cs&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;                &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;Completed&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-cs&quot;&gt;false&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;            &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;        &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-braces z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-cs&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;        &lt;span class=&quot;z-storage z-type z-variable z-cs&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-variable z-cs&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;todoList&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-cs&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-cs&quot;&gt;&lt;span class=&quot;z-variable z-function z-cs&quot;&gt;GetTodoList&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-cs&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-cs&quot;&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-cs&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-cs&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;        &lt;span class=&quot;z-variable z-other z-cs&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-cs&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-cs&quot;&gt;&lt;span class=&quot;z-variable z-function z-cs&quot;&gt;Should&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-cs&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-cs&quot;&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-cs&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-cs&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-cs&quot;&gt;&lt;span class=&quot;z-variable z-function z-cs&quot;&gt;BeEquivalentTo&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-cs&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-cs&quot;&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-variable z-other z-cs&quot;&gt;expected&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-cs&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-cs&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-block z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;ref&quot;&gt;Ref&lt;a class=&quot;zola-anchor&quot; href=&quot;#ref&quot; aria-label=&quot;Anchor link for: ref&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;fluentassertions.com&#x2F;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Cross published at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.dotnetthailand.com&#x2F;testing&#x2F;fluent-assertions&quot;&gt;.NET Thailand&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Acknowledgement: Thank you .net thailand team to review this article: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.dotnetthailand.com&quot;&gt;dotnetthailand.github.io&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Run C# scripts ไฟล์เดียว โดยใช้ .NET CLI</title>
		<published>2021-09-04T00:00:00+00:00</published>
		<updated>2021-09-04T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/run-c-sharp-scripts-from-dotnet-cli/" type="text/html"/>
		<id>https://thadaw.com/posts/run-c-sharp-scripts-from-dotnet-cli/</id>
		<content type="html">&lt;p&gt;วิธีการรัน C# ไฟล์เดียวโดยที่ไม่ต้องสร้างเป็นโปรเจ็คโดยใช้
.NET CLI&lt;&#x2F;p&gt;
&lt;p&gt;เนื่องจากได้รู้จักกับ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;leetcode.com&#x2F;&quot;&gt;LeetCode&lt;&#x2F;a&gt; เว็บสำหรับฝึกฝนทักษะการเขียนโปรแกรม โดยที่มีหลายภาษามากๆ และแน่นอนมีภาษา C# ด้วย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1-tidtang&quot;&gt;1. ติดตั้ง&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-tidtang&quot; aria-label=&quot;Anchor link for: 1-tidtang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;แค่ติดตั้ง dotnet-script โดยใช้คำสั่ง&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dotnet&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; tool install&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;g&lt;&#x2F;span&gt; dotnet-script&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;2-sraangaifl-omnisharp-json&quot;&gt;2. สร้างไฟล์ omnisharp.json&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-sraangaifl-omnisharp-json&quot; aria-label=&quot;Anchor link for: 2-sraangaifl-omnisharp-json&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json z-code&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-js&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-json&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Filename: omnisharp.json
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;script&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-js&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-json&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; เพื่อให้รู้ว่าเราจะเขียน dotnet แบบ script
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;enableScriptNuGetReferences&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-js&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-json&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; ใช้ .net 5
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;defaultTargetFramework&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;net5.0&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;ถ้าเราใช้คำสั่ง &lt;code&gt;dotnet script init&lt;&#x2F;code&gt; จะสร้างไฟล์ &lt;code&gt;omnisharp.json&lt;&#x2F;code&gt; แบบนี้ให้อัตโนมัติเลย&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;3-ekhiiynaiflthiit-ngkaarran&quot;&gt;3. เขียนไฟล์ที่ต้องการรัน&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-ekhiiynaiflthiit-ngkaarran&quot; aria-label=&quot;Anchor link for: 3-ekhiiynaiflthiit-ngkaarran&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;c#&quot; class=&quot;language-c# z-code&quot;&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-cs&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Filename: HelloWorld.csx
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-access z-cs&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-class z-cs&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-cs&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-class z-cs&quot;&gt;HelloWorld&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;    &lt;span class=&quot;z-storage z-modifier z-access z-cs&quot;&gt;public&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-cs&quot;&gt;string&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-method z-cs&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-cs&quot;&gt;GetString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method z-parameters z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-cs&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method z-parameters z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-cs&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method z-cs&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-cs&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-flow z-return z-cs&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Hello World&lt;span class=&quot;z-punctuation z-definition z-string z-end z-cs&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-cs&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-meta z-method z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-block z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-meta z-class z-body z-cs&quot;&gt;&lt;span class=&quot;z-meta z-block z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-cs&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-cs&quot;&gt;&lt;span class=&quot;z-variable z-other z-cs&quot;&gt;Console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-cs&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-cs&quot;&gt;&lt;span class=&quot;z-variable z-function z-cs&quot;&gt;WriteLine&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-cs&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-cs&quot;&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-cs&quot;&gt;new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-support z-type z-cs&quot;&gt;HelloWorld&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-cs&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-instance z-cs&quot;&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-cs&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-cs&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-cs&quot;&gt;&lt;span class=&quot;z-variable z-function z-cs&quot;&gt;GetString&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-cs&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-cs&quot;&gt;&lt;span class=&quot;z-meta z-group z-cs&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-cs&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-cs&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-cs&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถ้าเราสังเกตุเราสามารถเขียนคำสั่งนอก Class ได้เลย ซึ่งสะดวกมากๆ สำหรับการเขียน script&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ใน Docs เค้าแนะนำให้ใช้ &lt;code&gt;.csx&lt;&#x2F;code&gt; เพราะว่าจะได้แยกแยะออกว่าอันนี้คือ scripts&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;okhrngsraangaiflkhwrepnaebbnii&quot;&gt;โครงสร้างไฟล์ควรเป็นแบบนี้&lt;a class=&quot;zola-anchor&quot; href=&quot;#okhrngsraangaiflkhwrepnaebbnii&quot; aria-label=&quot;Anchor link for: okhrngsraangaiflkhwrepnaebbnii&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── HelloWorld.csx
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;└── omnisharp.json
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;4-aelwranaidely&quot;&gt;4. แล้วรันได้เลย&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-aelwranaidely&quot; aria-label=&quot;Anchor link for: 4-aelwranaidely&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; dotnet-script .&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\H&lt;&#x2F;span&gt;elloWorld.csx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Hello&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; World&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;tip-sraang-scripts-epn-folder&quot;&gt;Tip: สร้าง scripts เป็น folder&lt;a class=&quot;zola-anchor&quot; href=&quot;#tip-sraang-scripts-epn-folder&quot; aria-label=&quot;Anchor link for: tip-sraang-scripts-epn-folder&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เราสามารถใช้ โดยการสร้าง Folder ไว้แล้ว รันคำสั่งใน Folder นั้นเลย&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dotnet&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; script init&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will create &lt;code&gt;main.csx&lt;&#x2F;code&gt; along with the launch configuration needed to debug the script in VS Code.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── .vscode
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│   └── launch.json
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── main.csx
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;└── omnisharp.json
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;ref&quot;&gt;Ref&lt;a class=&quot;zola-anchor&quot; href=&quot;#ref&quot; aria-label=&quot;Anchor link for: ref&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;https:&#x2F;&#x2F;github.com&#x2F;filipw&#x2F;dotnet-script&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ตั้งค่าให้ Github Actions แสดง Previews Deploy เมื่อส่ง Pull Request โดยใช้ Vercel</title>
		<published>2021-08-27T00:00:00+00:00</published>
		<updated>2021-08-27T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/github-actions-previews-deploy-using-vercel/" type="text/html"/>
		<id>https://thadaw.com/posts/github-actions-previews-deploy-using-vercel/</id>
		<content type="html">&lt;p&gt;นี่เป็นตัวอย่างการใช้งานคร่าวๆ นะครับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;pull&#x2F;29&quot;&gt;Pull request example&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;github-actions-previews-deploy-using-vercel&#x2F;preview.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;withiikaaraich&quot;&gt;วิธีการใช้&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiikaaraich&quot; aria-label=&quot;Anchor link for: withiikaaraich&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1-thaamiikaarechuue-mt-vercel-kab-github-aihpidkaarechuue-mt-k-n&quot;&gt;1. ถ้ามีการเชื่อมต่อ Vercel กับ Github ให้ปิดการเชื่อมต่อก่อน&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-thaamiikaarechuue-mt-vercel-kab-github-aihpidkaarechuue-mt-k-n&quot; aria-label=&quot;Anchor link for: 1-thaamiikaarechuue-mt-vercel-kab-github-aihpidkaarechuue-mt-k-n&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เพราะว่าเราต้องการให้ github actions build and deploy แทนที่ Vercel (ซึ่งโดยปกติ Vercel จะ build และ deploy ให้อัตโนมัติ) &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;marketplace&#x2F;actions&#x2F;vercel-action#disable-vercel-for-github&quot;&gt;Read More&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Vercel for GitHub integration automatically deploys your GitHub projects with Vercel, providing Preview Deployment URLs, and automatic Custom Domain updates. &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;vercel.com&#x2F;docs&#x2F;v2&#x2F;git-integrations&quot;&gt;link&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Set &lt;code&gt;github.enabled&lt;&#x2F;code&gt;: false in &lt;code&gt;vercel.json&lt;&#x2F;code&gt;, see example &lt;code&gt;vercel.json&lt;&#x2F;code&gt; file below:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json z-code&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;version&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-json&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;public&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;github&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;enabled&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt;false&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;builds&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;    &lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;src&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;.&#x2F;public&#x2F;**&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;use&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;@now&#x2F;static&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;routes&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;    &lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;src&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;(.*)&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dest&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;public&#x2F;$1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When set to false, Vercel for GitHub will not deploy the given project regardless of the GitHub app being installed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-khunkhwrechuue-mt-github-kab-vercel-thiiekhruue-ngkh-ngkhun&quot;&gt;2. คุณควรเชื่อมต่อ Github กับ Vercel ที่เครื่องของคุณ&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-khunkhwrechuue-mt-github-kab-vercel-thiiekhruue-ngkh-ngkhun&quot; aria-label=&quot;Anchor link for: 2-khunkhwrechuue-mt-github-kab-vercel-thiiekhruue-ngkh-ngkhun&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;https:&#x2F;&#x2F;github.com&#x2F;marketplace&#x2F;actions&#x2F;vercel-action#project-linking&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; vercel&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Set up and deploy “&lt;span class=&quot;z-meta z-group z-expansion z-tilde&quot;&gt;&lt;span class=&quot;z-variable z-language z-tilde z-shell&quot;&gt;~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;web&#x2F;my-lovely-project”&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;Y&#x2F;n&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt; y&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Which scope do you want to deploy to&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;?&lt;&#x2F;span&gt; My Awesome Team&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Link to existing project&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;y&#x2F;N&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt; y&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; What’s the name of your existing project&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;?&lt;&#x2F;span&gt; my-lovely-project&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;🔗&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; Linked to awesome-team&#x2F;my-lovely-project (created .vercel and added it to .gitignore&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once set up, a new .vercel directory will be added to your directory. The .vercel directory contains both the organization(vercel-org-id) and project(vercel-project-id) id of your project.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json z-code&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;orgId&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;example_org_id&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;projectId&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;example_project_id&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;คุณสามารถเก็บ secret ได้ตาม &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;help.github.com&#x2F;en&#x2F;actions&#x2F;configuring-and-managing-workflows&#x2F;creating-and-storing-encrypted-secrets&quot;&gt;link&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-kamhnd-github-actions&quot;&gt;3. กำหนด Github Actions&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-kamhnd-github-actions&quot; aria-label=&quot;Anchor link for: 3-kamhnd-github-actions&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;TL;DR: Combining &lt;code&gt;pull_request_target&lt;&#x2F;code&gt; workflow trigger with an explicit checkout of an untrusted PR is a dangerous practice that may lead to repository compromise. We use &lt;code&gt;pull_request&lt;&#x2F;code&gt; trigger. &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;securitylab.github.com&#x2F;research&#x2F;github-actions-preventing-pwn-requests&#x2F;&quot;&gt;Ref&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre data-lang=&quot;yml&quot; class=&quot;language-yml z-code&quot;&gt;&lt;code class=&quot;language-yml&quot; data-lang=&quot;yml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt;# https:&#x2F;&#x2F;github.com&#x2F;marketplace&#x2F;actions&#x2F;vercel-action
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Preview deploy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-constant z-language z-boolean z-yaml&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;pull_request&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;branches&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;  &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;deploy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;runs-on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;ubuntu-latest&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;    &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;steps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;actions&#x2F;checkout@v2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;uses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;amondnet&#x2F;vercel-action@v20&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;vercel-action&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;vercel-token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets.VERCEL_TOKEN }}&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Required
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;github-token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }}&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt;Optional
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;vercel-org-id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets.VERCEL_ORG_ID}}&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt;Required
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;vercel-project-id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;${{ secrets.VERCEL_PROJECT_ID}}&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt;Required
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-sequence z-item z-yaml&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;preview-url&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-block-scalar z-literal z-yaml&quot;&gt;|&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-block z-yaml&quot;&gt;          echo ${{ steps.vercel-action.outputs.preview-url }}
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;4-kamhndkhaathiit-ngaich-thang-github-secrets-aela-vercel&quot;&gt;4. กำหนดค่าที่ต้องใช้ ทั้ง GitHub Secrets และ Vercel&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-kamhndkhaathiit-ngaich-thang-github-secrets-aela-vercel&quot; aria-label=&quot;Anchor link for: 4-kamhndkhaathiit-ngaich-thang-github-secrets-aela-vercel&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Secret key&lt;&#x2F;th&gt;&lt;th&gt;Secret value&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;VERCEL_TOKEN&lt;&#x2F;td&gt;&lt;td&gt;ต้องสร้างจาก https:&#x2F;&#x2F;vercel.com&#x2F;account&#x2F;tokens&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PUBLIC_REPO_ACCESS_TOKEN&lt;&#x2F;td&gt;&lt;td&gt;ต้องกำหนด &lt;strong&gt;repo&lt;&#x2F;strong&gt; access โดยกำหนด Token ของ github &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;github&#x2F;authenticating-to-github&#x2F;keeping-your-account-and-data-secure&#x2F;creating-a-personal-access-token&quot;&gt;read more&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;VERCEL_ORG_ID&lt;&#x2F;td&gt;&lt;td&gt;ID ของ team ที่เราใช้ แต่ถ้าใช้ Personal ให้เอาจาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;vercel.com&#x2F;account&quot;&gt;account setting&lt;&#x2F;a&gt; ใน Your ID&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;VERCEL_PROJECT_ID&lt;&#x2F;td&gt;&lt;td&gt;เอามาจาก Project ID ใน Project Setting&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;สำหรับการตั้งค่าอื่นๆ เพิ่มเติมที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;amondnet&#x2F;vercel-action&quot;&gt;Vercel Action - GitHub Action&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;read-more&quot;&gt;Read More&lt;a class=&quot;zola-anchor&quot; href=&quot;#read-more&quot; aria-label=&quot;Anchor link for: read-more&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;sanderknape.com&#x2F;2020&#x2F;05&#x2F;deploy-pull-requests-github-actions-deployments&#x2F;&quot;&gt;Deploy your pull requests with GitHub Actions and GitHub Deployments&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;securitylab.github.com&#x2F;research&#x2F;github-actions-preventing-pwn-requests&#x2F;&quot;&gt;Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Cross published at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.dotnetthailand.com&#x2F;programming-cookbook&#x2F;github-actions&#x2F;deploy-preview-when-pr&quot;&gt;.NET Thailand&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Acknowledgement: Thank you .net thailand team to review this article: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dotnetthailand&#x2F;dotnetthailand.github.io&#x2F;pull&#x2F;139&quot;&gt;dotnetthailand.github.io#139&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>React Import &amp; Export Component Pattern</title>
		<published>2021-08-21T00:00:00+00:00</published>
		<updated>2021-08-21T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/react-typescript-design-pattern-import-export/" type="text/html"/>
		<id>https://thadaw.com/posts/react-typescript-design-pattern-import-export/</id>
		<content type="html">&lt;h2 id=&quot;default-export&quot;&gt;Default export&lt;a class=&quot;zola-anchor&quot; href=&quot;#default-export&quot; aria-label=&quot;Anchor link for: default-export&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; MyComponent.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;MyComponent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;Hey, MyComponent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-default z-tsx&quot;&gt;default&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;MyComponent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; App.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;MyComponent&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.&#x2F;MyComponent&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;export&quot;&gt;Export&lt;a class=&quot;zola-anchor&quot; href=&quot;#export&quot; aria-label=&quot;Anchor link for: export&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; MyComponent.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;MyComponent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;Hey, MyComponent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; App.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;MyComponent&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.&#x2F;MyComponent&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;rename-import&quot;&gt;Rename import&lt;a class=&quot;zola-anchor&quot; href=&quot;#rename-import&quot; aria-label=&quot;Anchor link for: rename-import&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; MyComponent.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;MyComponent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;Hey, MyComponent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; App.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;MyComponent&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-tsx&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;MySuperComponent&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.&#x2F;MyComponent&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;App&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-support z-class z-component z-tsx&quot;&gt;MySuperComponent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-attributes z-tsx&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;group-all-imports-and-rename&quot;&gt;Group all imports and rename&lt;a class=&quot;zola-anchor&quot; href=&quot;#group-all-imports-and-rename&quot; aria-label=&quot;Anchor link for: group-all-imports-and-rename&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; MyComponent.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;Switch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;Hey, Switch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;Group&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;Hey, Group&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; App.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-import-export-all z-tsx&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-tsx&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;MyComponent&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.&#x2F;MyComponent&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;App&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;        &lt;span class=&quot;z-meta z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-support z-class z-component z-tsx&quot;&gt;MyComponent.Switch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-attributes z-tsx&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;        &lt;span class=&quot;z-meta z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-support z-class z-component z-tsx&quot;&gt;MyComponent.Group&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-attributes z-tsx&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;re-export-all&quot;&gt;Re-export all&lt;a class=&quot;zola-anchor&quot; href=&quot;#re-export-all&quot; aria-label=&quot;Anchor link for: re-export-all&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; MyComponent.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;Switch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;Hey, Switch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;Group&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;Hey, Group&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; MyParentComponent.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-import-export-all z-tsx&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;.&#x2F;MyComponent&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; App.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;Switch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;Group&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.&#x2F;MyParentComponent&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;App&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;        &lt;span class=&quot;z-meta z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-support z-class z-component z-tsx&quot;&gt;Switch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-attributes z-tsx&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;        &lt;span class=&quot;z-meta z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-support z-class z-component z-tsx&quot;&gt;Group&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-attributes z-tsx&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;re-export-then-group-all-imports-and-rename&quot;&gt;Re-export, then group all imports and rename&lt;a class=&quot;zola-anchor&quot; href=&quot;#re-export-then-group-all-imports-and-rename&quot; aria-label=&quot;Anchor link for: re-export-then-group-all-imports-and-rename&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; MyComponent.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;Switch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;Hey, Switch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;Group&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;Hey, Group&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; MyParentComponent.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt;  &lt;span class=&quot;z-constant z-language z-import-export-all z-tsx&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-as z-tsx&quot;&gt;as&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;MyComponent&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;.&#x2F;MyComponent&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; App.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;MyComponent&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.&#x2F;MyParentComponent&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;App&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;        &lt;span class=&quot;z-meta z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-support z-class z-component z-tsx&quot;&gt;MyComponent.Switch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-attributes z-tsx&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;        &lt;span class=&quot;z-meta z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-support z-class z-component z-tsx&quot;&gt;MyComponent.Group&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-attributes z-tsx&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;export-type&quot;&gt;Export type&lt;a class=&quot;zola-anchor&quot; href=&quot;#export-type&quot; aria-label=&quot;Anchor link for: export-type&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; MyComponent.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-type z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-type z-tsx&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-alias z-tsx&quot;&gt;Gender&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Male&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-type z-tsx&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Female&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; Accept only &amp;quot;Male&amp;quot; or &amp;quot;Female&amp;quot;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; App.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;Gender&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.&#x2F;MyComponent&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;export-interface&quot;&gt;Export interface&lt;a class=&quot;zola-anchor&quot; href=&quot;#export-interface&quot; aria-label=&quot;Anchor link for: export-interface&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; MyComponent.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-interface z-tsx&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-tsx&quot;&gt;IUser&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-tsx&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-tsx&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-definition z-property z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-tsx&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-tsx&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; App.tsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;IUser&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.&#x2F;MyComponent&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Cross published at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.dotnetthailand.com&#x2F;frontend-web&#x2F;react-typescript&#x2F;design-pattern&quot;&gt;.NET Thailand&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Acknowledgement: Thank you .net thailand team to review this article: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dotnetthailand&#x2F;dotnetthailand.github.io&#x2F;pull&#x2F;84&#x2F;files&quot;&gt;dotnetthailand.github.io#84&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>จัดการ side effects ใน React ด้วย Hook useEffect</title>
		<published>2021-08-20T00:00:00+00:00</published>
		<updated>2021-08-20T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/react-typescript-design-pattern-use-effect/" type="text/html"/>
		<id>https://thadaw.com/posts/react-typescript-design-pattern-use-effect/</id>
		<content type="html">&lt;p&gt;Side effects เป็น function โดยส่วนใหญ่แล้ว เราจะจัดการกับ Side Effect ของ Component โดยมี 3 scenarios:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ทำงานเฉพาะครั้งแรกที่ Component mount (Only when a component mounts)&lt;&#x2F;li&gt;
&lt;li&gt;เคลียร์ค่าต่างๆ โดยใช้ return a function (Cleaning up by returning a function)&lt;&#x2F;li&gt;
&lt;li&gt;ทำงานเมื่อ dependencies มีการเปลี่ยนแปลง (Running when specific dependencies change)a&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;1-thamngaanechphaaakhrangaerkthii-component-mount&quot;&gt;1. ทำงานเฉพาะครั้งแรกที่ Component mount&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-thamngaanechphaaakhrangaerkthii-component-mount&quot; aria-label=&quot;Anchor link for: 1-thamngaanechphaaakhrangaerkthii-component-mount&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จะทำครั้งแรก ครั้งเดียวเมื่อ Component โหลดเสร็จ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-tsx&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;FirstExecuteComponent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-tsx&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; Add event listeners (Flux Store, WebSocket, document, etc.)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;useEffect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-tsx&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-tsx&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Component loaded&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-square z-tsx&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-tsx&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-null z-tsx&quot;&gt;null&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ข้อสังเกตุ &lt;code&gt;useEffect&lt;&#x2F;code&gt; ต้องการรับ 2 parameters ถ้าอยากให้เหมือน &lt;code&gt;componentDidMount()&lt;&#x2F;code&gt; ให้ใส่ Array เปล่าๆ ใน parameters ตัวที่สอง &lt;code&gt;[]&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-ekhliiyrkhaataang-odyaich-return-a-function&quot;&gt;2. เคลียร์ค่าต่างๆ โดยใช้ return a function&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-ekhliiyrkhaataang-odyaich-return-a-function&quot; aria-label=&quot;Anchor link for: 2-ekhliiyrkhaataang-odyaich-return-a-function&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จะทำงานครั้งสุดท้ายครั้งเดียวก่อนที่ Component ถูกเอาออก (Component is unmounted and destroyed)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-tsx&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;FirstAndLastExecuteComponent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-tsx&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; Remove event listeners (Flux Store, WebSocket, document, etc.)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;useEffect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-tsx&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-tsx&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Component loaded&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-tsx&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-tsx&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Component unloaded&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-square z-tsx&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-tsx&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-null z-tsx&quot;&gt;null&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เราสามารถใช้ประโยชน์จาก function &lt;code&gt;useEffect&lt;&#x2F;code&gt; ได้ ตรงที่ return ของ parameters ตัวแรกของ &lt;code&gt;useEffect&lt;&#x2F;code&gt; โดยเราสามารถ remove event listeners หรือล้างข้อมูลอะไรบางอย่าง ก็ได้ครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;taw-yaangkaarekhliiyrkhaa-eventlistener-kh-ng-window-resize&quot;&gt;ตัวอย่างการเคลียร์ค่า EventListener ของ Window Resize&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangkaarekhliiyrkhaa-eventlistener-kh-ng-window-resize&quot; aria-label=&quot;Anchor link for: taw-yaangkaarekhliiyrkhaa-eventlistener-kh-ng-window-resize&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;useState&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;useEffect&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;react&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-tsx&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;getWindowSize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-tsx&quot;&gt;width&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-tsx&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-variable z-dom z-tsx&quot;&gt;window&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-tsx&quot;&gt;innerWidth&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-tsx&quot;&gt;height&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-tsx&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-variable z-dom z-tsx&quot;&gt;window&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-tsx&quot;&gt;innerHeight&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-tsx&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-default z-tsx&quot;&gt;default&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-tsx&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;WindowSize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-array-binding-pattern-variable z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-array z-tsx&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;size&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;setSize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-array z-tsx&quot;&gt;]&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;useState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;getWindowSize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;useEffect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;handleResize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;      &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;setSize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;getWindowSize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-support z-variable z-dom z-tsx&quot;&gt;window&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-tsx&quot;&gt;addEventListener&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;resize&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;handleResize&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-support z-variable z-dom z-tsx&quot;&gt;window&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-tsx&quot;&gt;removeEventListener&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;resize&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;handleResize&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-tsx&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-tsx&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;      Width: &lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-tsx&quot;&gt;size&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-tsx&quot;&gt;width&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt;, Height: &lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-tsx&quot;&gt;size&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-tsx&quot;&gt;height&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;3-thamngaanemuue-dependencies-miikaarepliiynaeplng&quot;&gt;3. ทำงานเมื่อ dependencies มีการเปลี่ยนแปลง&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-thamngaanemuue-dependencies-miikaarepliiynaeplng&quot; aria-label=&quot;Anchor link for: 3-thamngaanemuue-dependencies-miikaarepliiynaeplng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เราสามารถใส่ dependencies ที่อยากตรวจสอบได้ เช่น เมื่อ toggle มีการเปลี่ยนแปลงค่า จากที่ User เป็นคนคลิก ให้เรียก side effect เป็นต้น ดังตัวอย่างข้างล่างนี้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;useState&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;useEffect&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;react&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-default z-tsx&quot;&gt;default&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-tsx&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;DetectChange&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-array-binding-pattern-variable z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-array z-tsx&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;toggle&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;setToggle&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-array z-tsx&quot;&gt;]&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;useState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean z-false z-tsx&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-array-binding-pattern-variable z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-array z-tsx&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;setMessage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-array z-tsx&quot;&gt;]&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;useState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;useEffect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;toggleMessage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;toggle&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-tsx&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;True&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;False&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;setMessage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;toggleMessage&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-tsx&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;toggle&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-tsx&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;      &lt;span class=&quot;z-meta z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;button&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-attributes z-tsx&quot;&gt; &lt;span class=&quot;z-entity z-other z-attribute-name z-tsx&quot;&gt;onClick&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;setToggle&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-tsx&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;toggle&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;Toggle&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;button&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;      &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;h1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;h1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note: ตัวอย่างนี้ไม่ใช่วิธีการที่ดีในการควบคุม state เขียนอธิบายการทำงานเท่านั้น&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Cross published at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.dotnetthailand.com&#x2F;frontend-web&#x2F;react-typescript&#x2F;design-pattern&quot;&gt;.NET Thailand&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Acknowledgement: Thank you .net thailand team to review this article: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dotnetthailand&#x2F;dotnetthailand.github.io&#x2F;pull&#x2F;84&#x2F;files&quot;&gt;dotnetthailand.github.io#84&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ย้ายจาก React Class Component มาเป็น Functional Component ง่ายกว่าที่คิด</title>
		<published>2021-08-05T00:00:00+00:00</published>
		<updated>2021-08-05T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/migrate-react-class-component-to-functional-component/" type="text/html"/>
		<id>https://thadaw.com/posts/migrate-react-class-component-to-functional-component/</id>
		<content type="html">&lt;p&gt;ใครที่ใช้ React แล้วเขียนด้วย Class Componentลองย้ายมาเขียน Functional Component (Hook) ดูน้า ไม่ยากเลย
ทำให้โค๊ดอ่านง่ายมากขึ้นด้วย และเขียนง่ายขึ้น&lt;&#x2F;p&gt;
&lt;p&gt;วันนี้เอาตัวอย่างที่ใช้บ่อยๆ ใน React TypeScript เทียบกันให้เห็น จะๆ เลย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;local-state&quot;&gt;Local State&lt;a class=&quot;zola-anchor&quot; href=&quot;#local-state&quot; aria-label=&quot;Anchor link for: local-state&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เราสามารถแปลงจาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;react-typescript-cheatsheet.netlify.app&#x2F;docs&#x2F;basic&#x2F;getting-started&#x2F;class_components&#x2F;&quot;&gt;Class Component&lt;&#x2F;a&gt; ด้านล่างนี้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;React&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;react&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-interface z-tsx&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-tsx&quot;&gt;MyProps&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-tsx&quot;&gt;message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-tsx&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-interface z-tsx&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-tsx&quot;&gt;MyState&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-tsx&quot;&gt;count&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-tsx&quot;&gt;number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-tsx&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-tsx&quot;&gt;App&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-tsx&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-tsx&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-tsx&quot;&gt;Component&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-tsx&quot;&gt;MyProps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-tsx&quot;&gt;MyState&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-tsx&quot;&gt;state&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-tsx&quot;&gt;MyState&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-tsx&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; optional second annotation for better type inference&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-tsx&quot;&gt;count&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-tsx&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-tsx&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;render&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;      &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-tsx&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-tsx&quot;&gt;props&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-tsx&quot;&gt;message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-tsx&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-tsx&quot;&gt;state&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-tsx&quot;&gt;count&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ให้เป็น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;react-typescript-cheatsheet.netlify.app&#x2F;docs&#x2F;basic&#x2F;getting-started&#x2F;function_components&quot;&gt;Functional Component&lt;&#x2F;a&gt; แบบนี้ได้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;useState&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;react&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-interface z-tsx&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-tsx&quot;&gt;PropTypes&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-tsx&quot;&gt;message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-tsx&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-tsx&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;App&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-tsx&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-tsx&quot;&gt;message&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-tsx&quot;&gt;PropTypes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-array-binding-pattern-variable z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-array z-tsx&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;count&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;setCount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-array z-tsx&quot;&gt;]&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;useState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-tsx&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;      &lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;count&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-default z-tsx&quot;&gt;default&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;App&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ทำไมถึงไม่แนะนำ &lt;code&gt;React.FC&lt;&#x2F;code&gt; หรือ &lt;code&gt;React.FunctionComponent&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;React.VoidFunctionComponent&lt;&#x2F;code&gt; อ่านรายละเอียดใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;react-typescript-cheatsheet.netlify.app&#x2F;docs&#x2F;basic&#x2F;getting-started&#x2F;function_components&quot;&gt;Functional Component&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;handle-click-event&quot;&gt;Handle Click Event&lt;a class=&quot;zola-anchor&quot; href=&quot;#handle-click-event&quot; aria-label=&quot;Anchor link for: handle-click-event&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เราสามารถแปลงจาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;react-typescript-cheatsheet.netlify.app&#x2F;docs&#x2F;basic&#x2F;getting-started&#x2F;class_components&quot;&gt;Class Component&lt;&#x2F;a&gt; ด้านล่างนี้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;React&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;react&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-interface z-tsx&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-tsx&quot;&gt;PropTypes&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-tsx&quot;&gt;message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-tsx&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-interface z-tsx&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-tsx&quot;&gt;StateTypes&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-tsx&quot;&gt;counter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-tsx&quot;&gt;number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-tsx&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-tsx&quot;&gt;App&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-tsx&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-tsx&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-tsx&quot;&gt;Component&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-tsx&quot;&gt;PropTypes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-tsx&quot;&gt;StateTypes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-tsx&quot;&gt;state&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-tsx&quot;&gt;StateTypes&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-tsx&quot;&gt;counter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-tsx&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-tsx&quot;&gt;0&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-tsx&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;handleClick&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-tsx&quot;&gt;amount&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-tsx&quot;&gt;number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-tsx&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;setState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-tsx&quot;&gt;state&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-tsx&quot;&gt;counter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-tsx&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-tsx&quot;&gt;state&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-tsx&quot;&gt;counter&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-tsx&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;amount&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-tsx&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;render&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;      &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;        &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;h1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-tsx&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-tsx&quot;&gt;props&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-tsx&quot;&gt;message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;h1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;        &lt;span class=&quot;z-meta z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;button&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-attributes z-tsx&quot;&gt; &lt;span class=&quot;z-entity z-other z-attribute-name z-tsx&quot;&gt;onClick&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-tsx&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;handleClick&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-tsx&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt; Increase &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;button&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;        &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-tsx&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-tsx&quot;&gt;state&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-tsx&quot;&gt;counter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-class z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-default z-tsx&quot;&gt;default&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;App&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Using an arrow function in render creates a new function each time the component renders, which may break optimizations based on strict identity comparison. Read more at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;docs&#x2F;faq-functions.html#arrow-function-in-render&quot;&gt;React Official Doc&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ให้เป็น Functional Component แบบนี้ได้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-import z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-tsx&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-alias z-tsx&quot;&gt;useState&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-from z-tsx&quot;&gt;from&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;react&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-interface z-tsx&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-interface z-tsx&quot;&gt;PropTypes&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-tsx&quot;&gt;message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-tsx&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-interface z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-tsx&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;App&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-tsx&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-tsx&quot;&gt;message&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-tsx&quot;&gt;PropTypes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-array-binding-pattern-variable z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-array z-tsx&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;counter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;setCounter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-array z-tsx&quot;&gt;]&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;useState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-tsx&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-tsx&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;handleClick&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-tsx&quot;&gt;amount&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-tsx&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-primitive z-tsx&quot;&gt;number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;setCounter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;counter&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-tsx&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;amount&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;      &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;h1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;h1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;      &lt;span class=&quot;z-meta z-tag z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;button&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-attributes z-tsx&quot;&gt; &lt;span class=&quot;z-entity z-other z-attribute-name z-tsx&quot;&gt;onClick&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-tsx&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;handleClick&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-tsx&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt; Increase &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;button&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;      &lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-begin z-tsx&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-embedded z-expression z-tsx&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;counter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-embedded z-end z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-tag z-without-attributes z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-jsx z-children z-tsx&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-tsx&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-tsx&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-tsx&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-tsx&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-tsx&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-default z-tsx&quot;&gt;default&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-tsx&quot;&gt;App&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;componentdidmount-in-react-hook&quot;&gt;componentDidMount() in React Hook&lt;a class=&quot;zola-anchor&quot; href=&quot;#componentdidmount-in-react-hook&quot; aria-label=&quot;Anchor link for: componentdidmount-in-react-hook&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หนึ่งใน React Lifecyle ที่ใช้บ่อยๆ มากๆ คือ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;docs&#x2F;react-component.html#componentdidmount&quot;&gt;componentDidMount()&lt;&#x2F;a&gt; ซึ่งจะทำครั้งแรก ครั้งเดียวเมื่อ Component โหลดเสร็จ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-tsx&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;FirstExecuteComponent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-tsx&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; add event listeners (Flux Store, WebSocket, document, etc.)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;useEffect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-tsx&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-tsx&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Component loaded&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-square z-tsx&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-tsx&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-null z-tsx&quot;&gt;null&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ข้อสังเกตุ &lt;code&gt;useEffect&lt;&#x2F;code&gt; ต้องการรับ 2 parameters ถ้าอยากให้เหมือน &lt;code&gt;componentDidMount()&lt;&#x2F;code&gt; ให้ใส่ Array เปล่าๆ ใน parameters ตัวที่สอง &lt;code&gt;[]&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;componentwillunmount-in-react-hook&quot;&gt;componentWillUnmount() in React Hook&lt;a class=&quot;zola-anchor&quot; href=&quot;#componentwillunmount-in-react-hook&quot; aria-label=&quot;Anchor link for: componentwillunmount-in-react-hook&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;อีกหนึ่งใน React Lifecyle ที่มีใช้บ้างคือคือ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;docs&#x2F;react-component.html#componentwillunmount&quot;&gt;componentWillUnmount()&lt;&#x2F;a&gt; ซึ่งจะทำงานครั้งสุดท้ายครั้งเดียวก่อนที่ Component ถูกเอาออก (Component is unmounted and destroyed)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx z-code&quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-tsx&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;FirstAndLastExecuteComponent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-tsx&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-tsx&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-tsx&quot;&gt; remove event listeners (Flux Store, WebSocket, document, etc.)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-tsx&quot;&gt;useEffect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-tsx&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-tsx&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Component loaded&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-tsx&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-tsx&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-tsx&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-tsx&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-tsx&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Component unloaded&lt;span class=&quot;z-punctuation z-definition z-string z-end z-tsx&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-tsx&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-tsx&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-square z-tsx&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-tsx&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-tsx&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-tsx&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-null z-tsx&quot;&gt;null&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-tsx&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-function z-tsx&quot;&gt;&lt;span class=&quot;z-meta z-block z-tsx&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-tsx&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เราสามารถใช้ประโยชน์จาก function &lt;code&gt;useEffect&lt;&#x2F;code&gt; ได้ ตรงที่ return ของ parameters ตัวแรกของ &lt;code&gt;useEffect&lt;&#x2F;code&gt; โดยเราสามารถ remove event listeners หรือล้างข้อมูลอะไรบางอย่าง ก็ได้ครับ&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Cross published at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.dotnetthailand.com&#x2F;frontend-web&#x2F;react-typescript&#x2F;migrate-class-component-to-functional-component&quot;&gt;.NET Thailand&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Acknowledgement: Thank you .net thailand team to review this article: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dotnetthailand&#x2F;dotnetthailand.github.io&#x2F;pull&#x2F;83&#x2F;files&quot;&gt;dotnetthailand.github.io#83&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>เราควรเพิ่มประสิทธิภาพของ Single Page Application โดยใช้ Server-side Rendering (SSR) หรือไม่</title>
		<published>2021-06-29T00:00:00+00:00</published>
		<updated>2021-06-29T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/server-side-rendering-in-spa-and-seo/" type="text/html"/>
		<id>https://thadaw.com/posts/server-side-rendering-in-spa-and-seo/</id>
		<content type="html">&lt;p&gt;ได้มีโอกาสคุยกับพี่ชาย ก็ยังรู้สึกว่าหลายๆ คนยังไม่รู้จักคำว่า SSR หรือ Server-side Rendering บวกกับการมาของ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;blog&#x2F;2021&#x2F;06&#x2F;08&#x2F;the-plan-for-react-18.html&quot;&gt;React 18&lt;&#x2F;a&gt; ที่นำเสนอ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=TQQPAU21ZUw&quot;&gt;Server Component&lt;&#x2F;a&gt; เลยรู้สึกตื่นเต้น วันนี้เลยอยากมาแชร์ให้ฟังกันครับ&lt;&#x2F;p&gt;
&lt;p&gt;ต้องบอกว่า SSR มาพร้อมกับการเขียน JavaScript ยุคสมัยใหม่ เช่น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;&quot;&gt;React&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;vuejs.org&#x2F;&quot;&gt;Vue&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;angular.io&#x2F;&quot;&gt;Angular&lt;&#x2F;a&gt; ที่เราไม่แก้ไข DOM ตรงๆ แต่ใช้กลไกบางอย่างที่ทำให้แก้ไข DOM เท่าที่จำเป็นเท่านั้น เช่น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;docs&#x2F;faq-internals.html&quot;&gt;Virtual DOM&lt;&#x2F;a&gt; ทำให้ประสิทธิภาพดีขึ้นกว่าการเขียนแบบเดิมๆ เช่น Vanilla JavaScript หรือใช้ jQuery นั้นเอง เดี๋ยวเราจะคุยประเด็นนี้ในบทความต่อนะครับ&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Vanilla เป็น Adjective ที่มาขยายการเขียนด้วย JavaScript เพื่อมาเน้นว่านี้คือการเขียน JavaScript ล้วนๆ นะ ไม่มีอะไรอื่นมาผสม&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;ssr-aimaicheruue-ngaihm&quot;&gt;SSR ไม่ใช่เรื่องใหม่&lt;a class=&quot;zola-anchor&quot; href=&quot;#ssr-aimaicheruue-ngaihm&quot; aria-label=&quot;Anchor link for: ssr-aimaicheruue-ngaihm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ถ้าย้อนกลับไปเมื่อ 10 กว่าปีที่แล้ว สมัยที่เราเขียน PHP เพื่อทำ Web Application ซึ่ง PHP เองก็ภาษาฝั่ง Server หมายความว่า PHP source code จะถูก interpret ที่ server แล้วส่ง response กลับมาเป็น HTML มายัง Client ลองมาดูรูปประกอบเพื่อให้เห็นภาพมากขึ้น&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;server-side-rendering-in-spa-and-seo&#x2F;01-regular-web-application.png&quot; alt=&quot;regular-web-application&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;จากในรูปในขั้นตอนที่ 3 server ก็จะ interpret ให้เป็น HTML แล้วส่งกลับให้ User ให้เห็น Result ของเว็บไซต์&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งภาษาฝั่ง Server จะเป็น PHP, Java, Node.js, C#, Go หรืออะไรก็แล้วแต่ ทำหน้าที่รับ request จาก user แล้วแปลงผลเท่านั้น&lt;&#x2F;p&gt;
&lt;p&gt;คำถามต่อไป คือแล้ว JavaScript ถูกทำงานที่ไหน แน่นอนว่าต้องเป็นที่ Browser อยู่แล้ว ซึ่งโดย Server จะส่ง HTML + CSS + JavaScript เมื่อ Browser โหลด HTML และ CSS เสร็จก็เรียกให้ JavaScript ทำงาน&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: เพื่อป้องกันการสับสน ถึงแม้ว่า NodeJS จะเขียนด้วยภาษา JavaScript ที่ทำงานอยู่บน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nodejs.org&#x2F;&quot;&gt;JavaScript runtime built on Chrome&#x27;s V8 JavaScript engine&lt;&#x2F;a&gt; ซึ่งทำหน้าที่ execute จาก JavaScript เป็น HTML Response (ที่รวม CSS และ JavaScript (ฝั่ง Client) เข้าด้วยกัน) จากนั้น JavaScript ที่เป็น Client Side จะถูกเรียกก็ต้องเมื่อโหลดบน Browser เท่านั้น&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;ssr-epnklaikpktikh-ng-web-application&quot;&gt;SSR เป็นกลไกปกติของ Web Application&lt;a class=&quot;zola-anchor&quot; href=&quot;#ssr-epnklaikpktikh-ng-web-application&quot; aria-label=&quot;Anchor link for: ssr-epnklaikpktikh-ng-web-application&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ถ้าเราสังเกตุกลไกการทำงานของ Web Application นั้น มันคือการ render HTML ที่ฝั่ง server ซึ่งก็ตรงตัวกับคำว่า Server-side Rendering ที่หมายถึงการ Render ที่ฝั่ง Server นั้นเอง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;mii-web-application-yuuaelw-aelwthamaimt-ngmii-ssr-iik&quot;&gt;มี Web Application อยู่แล้ว แล้วทำไมต้องมี SSR อีก ?&lt;a class=&quot;zola-anchor&quot; href=&quot;#mii-web-application-yuuaelw-aelwthamaimt-ngmii-ssr-iik&quot; aria-label=&quot;Anchor link for: mii-web-application-yuuaelw-aelwthamaimt-ngmii-ssr-iik&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;แบบนี้ครับ จากต้นบทความผมได้บอกไปแล้วว่า SSR
มาพร้อมกับการเขียน JavaScript ยุคสมัยใหม่ เช่น React, Vue, Angular เป็นต้น&lt;&#x2F;p&gt;
&lt;p&gt;SSR เกิดมาขึ้นมาจากการเขียน SPA หรือ Single Page Application ครับ ต้องบอกว่า React, Vue, Angular ทำให้การเขียน Single Page Application เป็นที่นิยมมากในปัจจุบัน ซึ่ง SPA สาเหตุที่เรียกว่า SPA ก็คือมันมีหน้าเดียวครับ การ Routing เกิดขึ้นที่ Client ไม่ใช่ Server&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Routing คือ ตัวกลางในการจัดการว่าเมื่อมีการเข้าถึง URL หรือ Path นั้น ของเว็บให้ไปเรียก Controller หรือตัวที่เกี่ยวข้องมาจัดการครับ เช่น https:&#x2F;&#x2F;mydomain.com ต้องไปเรียก Controller ที่เป็น Index หรือ https:&#x2F;&#x2F;mydomain.com&#x2F;users ต้องไปเรียก Controller ที่จัดการ path &lt;code&gt;&#x2F;users&lt;&#x2F;code&gt; ว่าต้องทำยังไงต่อไป&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;กลับมาที่ Web Application ทั่วไป Routing จะอยู่ที่ server ครับ เมื่อมีการเข้าถึง Path  หรือ URL อื่นๆ ตัว Routing ก็จะต้องไปเรียก controller นั้นๆ มาจัดการส่งหน้า HTML ให้ client บางที่เค้าถึงเรียกว่า Multi-Page Application&lt;&#x2F;p&gt;
&lt;p&gt;กลับมาที่ SPA ที่เป็นการ Routing แบบที่เกิดขึ้นที่ Client ดังนั้นเมื่อ Routing เกิดขึ้นที่ client ตัวที่ควบคุมกลไกต่างๆ จึงเป็นหน้าที่ของ JavaScript ที่โหลดมาแค่หน้าเดียวแต่สามารถใช้ URL ที่แตกต่างกันเข้าถึงได้ โดยที่ไม่ต้องพึงพา server เลย&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bthbaathkh-ng-spa-rwmthuengkh-diiaelakh-esiiy&quot;&gt;บทบาทของ SPA รวมถึงข้อดีและข้อเสีย&lt;a class=&quot;zola-anchor&quot; href=&quot;#bthbaathkh-ng-spa-rwmthuengkh-diiaelakh-esiiy&quot; aria-label=&quot;Anchor link for: bthbaathkh-ng-spa-rwmthuengkh-diiaelakh-esiiy&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ในยุคที่ React, Vue, Angular มีความนิยมสูงขึ้นมาก มันจึงทำให้การทำ SPA เป็นเรื่องที่ง่ายขึ้นกว่าแต่ก่อนมากๆ รวมถึงการผลักดัน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.dev&#x2F;progressive-web-apps&#x2F;&quot;&gt;PWA Application โดย Google&lt;&#x2F;a&gt;  ซึ่งบทบาทของ SPA หลักๆ คือการมาแทนที่ Mobile Application อย่างพวก Android หรือ iOS ได้ (ไม่ได้ทุกกรณี ขึ้นอยู่กับ Requirement)&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;เราอาจจะเรียก SPA ว่าเป็น CSR (Client-side Rendering) ก็ได้ ถ้า SPA นั้น Render บน client ทั้งหมด จากนี้ขอเรียกว่า CSR แทน SPA เพื่อให้ชัดเจนขึ้นว่า SPA ใช้ Approach CSR.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ข้อดีของ SPA ที่เป็น CSR ก็มีหลายอย่างเช่นกัน User Experience ดีขึ้น ความไหลลื่นในการใช้งาน เพราะลดช่องว่างของการรอระหว่างเปลี่ยนหน้า ซึ่งเกิดจากการรอ response จาก server หรือ การเก็บ Cache ข้อมูลเพื่อให้โหลดข้อมูลได้เร็วขึ้น หรือแม้แต่การใช้ประโยชน์จาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;web&#x2F;fundamentals&#x2F;primers&#x2F;service-workers&quot;&gt;Service Worker&lt;&#x2F;a&gt; ในการทำ background process เช่น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;web&#x2F;fundamentals&#x2F;push-notifications&quot;&gt;push notifications&lt;&#x2F;a&gt; และ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;web&#x2F;updates&#x2F;2015&#x2F;12&#x2F;background-sync&quot;&gt;background sync&lt;&#x2F;a&gt; เป็นต้น
หรือการที่เราสามารถ ติดตั้ง SPA ลงเป็นแอพ​ในมือถือได้เลย (โดยใช้ PWA)&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@firt&#x2F;progressive-web-apps-on-ios-are-here-d00430dee3a7&quot;&gt;PWA บน iOS 12&lt;&#x2F;a&gt; , &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;firt.dev&#x2F;ios-14&#x2F;&quot;&gt;PWA บน iOS 14&lt;&#x2F;a&gt; ยังมีข้อจำกัดในหลายๆ เรื่อง&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;อีกหนึ่งข้อดีของ SSR คือ การที่ Library บาง Library อาจจะช่วยลด development cost ได้โดยที่สามารถ Passing value ผ่านเข้า prop โดยตรง โดยที่ไม่ต้อง implement API endpoint ขึ้นมาใหม่ ยกตัวอย่าง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;reactjs.net&#x2F;&quot;&gt;ReactJS.net&lt;&#x2F;a&gt; ที่สามารถส่ง value จาก backend server ไปยังไง view ได้เลย สังเกตุจากใน code ข้างล่าง&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;html&quot; class=&quot;language-html z-code&quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-comment z-block z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-html&quot;&gt;&amp;lt;!--&lt;&#x2F;span&gt; This will render the component server-side &lt;span class=&quot;z-punctuation z-definition z-comment z-end z-html&quot;&gt;--&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;@Html.React(&amp;quot;CommentsBox&amp;quot;, new {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    initialComments = Model.Comments
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;})
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ถ้าสังเกตุจาก code React components จะต้องถูกส่งค่าจาก components อื่นใน JavaScript แต่ในนี้ เราส่งค่า &lt;code&gt;Model.Comments&lt;&#x2F;code&gt; ผ่าน props ที่ชื่อว่า &lt;code&gt;initialComments&lt;&#x2F;code&gt; ได้โดยตรงเลย&lt;&#x2F;p&gt;
&lt;p&gt;ส่วนข้อเสียของ SPA ก็อาจจะเป็น Development Cost ที่สูงขึ้น ถ้าเทียบกับ Web Application (อย่างไร ก็ตามขึ้นอยู่กับความชำนาญของทีมด้วย) เพราะไม่ใช่แค่ Web ที่แสดงผลของจาก backend server แต่ยังต้อง manage state จัดการ authentication หรือ authorization หรืออื่นๆ อีกมากมาย (มากหรือน้อย ขึ้นอยู่กับ requirement)&lt;&#x2F;p&gt;
&lt;p&gt;อีกหนึ่งข้อเสียของ SPA ที่จะไม่พูดไม่ได้เลย และเป็นที่มาของบทความนี้คือ ระยะเวลาในการโหลดครั้งแรกสูง (High Initial Load) เมื่อเทียบกับ SSR&lt;&#x2F;p&gt;
&lt;p&gt;เพื่อให้เห็นภาพมากขึ้นจากรูป SSR และ CSR&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;server-side-rendering-in-spa-and-seo&#x2F;02-csr-vs-ssr.png&quot; alt=&quot;CSR vs SSR redrawn from https:&#x2F;&#x2F;blog.logrocket.com&#x2F;next-js-vs-create-react-app&#x2F;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: รูปนี้อาจจะไม่ใช่ การ implement SSR ในรูปแบบทั่วไป แต่วาดออกมาเพื่อยกตัวอย่างให้เห็นภาพ เพราะจริงๆ SSR เอง อธิบายแค่การ Render พร้อม data จาก server แล้วเท่านั้นเอง โดยรูปดังกล่าวเป็นการวาดโดยอ้างจากหลักการทำ SSR เบื้องต้นใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nextjs.org&#x2F;&quot;&gt;Next.js&lt;&#x2F;a&gt; ซึ่งมีการอธิบายเปรียบเทียบอย่างดีแล้วใน&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;blog.logrocket.com&#x2F;next-js-vs-create-react-app&#x2F;&quot;&gt;บทความของ logrocket ที่เปรียบ Next.js กับ Create React App&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ถ้าเราดูจากรูป CSR ทางซ้ายมือ ในขั้นที่ 2 ที่เว็บโหลดขึ้นมา เรายังไม่ได้ Data มาเลย อาจจะมีแค่ UI หรือจะมี Spinner รอโหลดข้อมูลมา ตัว client จะต้องส่งไปขอข้อมูลมาจากเว็บ อีกรอบถึงจะแสดงว่าเว็บที่สมบูรณ์ได้&lt;&#x2F;p&gt;
&lt;p&gt;ในขณะที่ SSR ทางขวามือ ในขั้นที่ 3 เราก็สามารถได้ หน้าเว็บที่สมบูรณ์ได้เลย เพราะในขั้นตอนที่ 2 ก่อนที่ server จะส่งออกมา ก็ทำจากเรียก API จากตัว server เลย ทำให้ประหยัดเวลากว่า&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aelwekhruue-ngmuue-ainpacchcchubanmiiaebbaihnkanbaang&quot;&gt;แล้วเครื่องมือในปัจจุบันมีแบบไหนกันบ้าง&lt;a class=&quot;zola-anchor&quot; href=&quot;#aelwekhruue-ngmuue-ainpacchcchubanmiiaebbaihnkanbaang&quot; aria-label=&quot;Anchor link for: aelwekhruue-ngmuue-ainpacchcchubanmiiaebbaihnkanbaang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;ตัวแรกเลยคือ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;docs&#x2F;create-a-new-react-app.html&quot;&gt;Create React App&lt;&#x2F;a&gt; โดยเราสามารถเขียน SPA แบบ CSR ได้โดย default เลย แต่ถ้าจะทำ SSR ใน official docs เค้าแนะนำให้ไปใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nextjs.org&#x2F;&quot;&gt;Next.js&lt;&#x2F;a&gt; แทน ซึ่งทำได้ดีๆ มากๆ
&lt;ul&gt;
&lt;li&gt;แต่ข้อเสียคือ เราอาจจะต้องใช้ backend server ที่เป็น JavaScript&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;ส่วนถ้าเป็นการทำ SSR ภาษาอื่นๆ ก็สามารถทำได้ครับ แต่อาจจะต้อง customize เองเช่น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;reactjs.net&#x2F;&quot;&gt;ReactJS.net&lt;&#x2F;a&gt; ที่ทำงานร่วมกับ ASP.NET Core หรือภาษา Python, Java ก็มีเหมือนกัน&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: ขอไม่พูดถึง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.gatsbyjs.com&#x2F;&quot;&gt;Gatsby&lt;&#x2F;a&gt; เพราะวัตถุประสงค์การใช้งานต่างกัน ตัวนี้เหมาะสมสำหรับทำ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.netlify.com&#x2F;blog&#x2F;2020&#x2F;04&#x2F;14&#x2F;what-is-a-static-site-generator-and-3-ways-to-find-the-best-one&#x2F;&quot;&gt;Static Site Generator&lt;&#x2F;a&gt; มากกว่า&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;hlakainkaareluue-k&quot;&gt;หลักในการเลือก&lt;a class=&quot;zola-anchor&quot; href=&quot;#hlakainkaareluue-k&quot; aria-label=&quot;Anchor link for: hlakainkaareluue-k&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;เลือก SSR
&lt;ul&gt;
&lt;li&gt;ถ้าอยากให้ Faster initial loading.&lt;&#x2F;li&gt;
&lt;li&gt;Improve SEO เพราะว่าการทำ Multi-Page จะทำให้ search engine ทำงานได้ดีกว่า และง่ายกว่า&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;เลือก CSR
&lt;ul&gt;
&lt;li&gt;ไม่ได้กังวลเรื่อง SEO มาก&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;แต่อย่างไรก็ตาม การทำ SEO บน SPA ก็เป็นเรื่องที่ท้าทาย ซึ่ง&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.searchenginewatch.com&#x2F;2018&#x2F;04&#x2F;09&#x2F;an-seos-survival-guide-to-single-page-applications-spas&#x2F;&quot;&gt;บทความของ Search Engine Watch&lt;&#x2F;a&gt; เขียนไว้ดีมาก และพูดเนื้อหาที่เป็นประโยชน์ในการเขียน SPA  เลือกใช้กลไก SSR หรือ CSR อย่างเหมาะสม เพราะการทำ SSR บางครั้งก็ใช้ development cost ที่สูงกว่าปกติ&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: ในบทความนี้ขอไม่พูดถึง Complex Architecture อย่าง Micro Frontend นะครับ เพราะถือว่าขึ้นอยู่กับการ Manage ไป อาจจะมีการ Mix กันหลายๆ Approach&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;aehlngkh-muuldii-samhrab-spa&quot;&gt;แหล่งข้อมูลดีๆ สำหรับ SPA&lt;a class=&quot;zola-anchor&quot; href=&quot;#aehlngkh-muuldii-samhrab-spa&quot; aria-label=&quot;Anchor link for: aehlngkh-muuldii-samhrab-spa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จาก&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.searchenginewatch.com&#x2F;2018&#x2F;04&#x2F;09&#x2F;an-seos-survival-guide-to-single-page-applications-spas&#x2F;&quot;&gt;บทความของ Search Engine Watch&lt;&#x2F;a&gt; ได้หยิบยกตัวอย่างข้อมูลดีๆ สำหรับทำ SEO บน SPA ผมเลยขอหยิบมาเขียนซ้ำอีกรอบ:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.elephate.com&#x2F;blog&#x2F;ultimate-guide-javascript-seo&#x2F;&quot;&gt;The Ultimate Guide to JavaScript SEO&lt;&#x2F;a&gt; by Tomasz Rudzki&lt;&#x2F;li&gt;
&lt;li&gt;General overview of Single Page Applications and how Google treats them: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=JlP5rBynK3E&quot;&gt;Watch this video&lt;&#x2F;a&gt; by Google ‎Senior Webmaster Trends Analyst &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;johnmu&#x2F;&quot;&gt;John Mueller&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.briggsby.com&#x2F;auditing-javascript-for-seo&#x2F;&quot;&gt;Auditing JavaScript for SEO&lt;&#x2F;a&gt;, and &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.briggsby.com&#x2F;dealing-with-javascript-for-seo&#x2F;&quot;&gt;Core Principles of SEO for JavaScript&lt;&#x2F;a&gt; by Justin Briggs&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;builtvisible.com&#x2F;javascript-framework-seo&#x2F;&quot;&gt;The Basics of JavaScript Framework SEO in AngularJS&lt;&#x2F;a&gt; by Richard Baxter&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.distilled.net&#x2F;resources&#x2F;split-testing-javascript-for-seo&#x2F;&quot;&gt;Early Results from Split Testing JavaScript for SEO&lt;&#x2F;a&gt; by Will Critchlow&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.stateofdigital.com&#x2F;javascript-seo-the-definitive-resource-list&#x2F;&quot;&gt;JavaScript &amp;amp; SEO: The Definitive Resource List&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;blog.twentysixdigital.com&#x2F;seo&#x2F;seo-considerations-for-single-page-applications&#x2F;&quot;&gt;SEO Considerations for Single Page Applications&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;blog.angular-university.io&#x2F;why-a-single-page-application-what-are-the-benefits-what-is-a-spa&#x2F;&quot;&gt;Angular Single Page Applications (SPA): What are the Benefits?&lt;&#x2F;a&gt; by Angular University&lt;&#x2F;li&gt;
&lt;li&gt;This Microsoft article: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;dotnet&#x2F;standard&#x2F;modern-web-apps-azure-architecture&#x2F;choose-between-traditional-web-and-single-page-apps&quot;&gt;Choose Between Traditional Web Apps and Single Page Apps (SPAs)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;A few different SPA types &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;blog.codecentric.de&#x2F;en&#x2F;2017&#x2F;12&#x2F;angular-single-page-applications&#x2F;&quot;&gt;by Johann Wagner&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Very good overview: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.scalablepath.com&#x2F;blog&#x2F;single-page-applications&#x2F;&quot;&gt;Single Page Applications: When &amp;amp; Why You Should Use Them&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;final-thought&quot;&gt;Final Thought&lt;a class=&quot;zola-anchor&quot; href=&quot;#final-thought&quot; aria-label=&quot;Anchor link for: final-thought&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;สุดท้ายนี้ การทำ SSR ก็ไม่ใช่วิธีการเดียวสำหรับการเพิ่มประสิทธิภาพ แต่เราสามารถใช้ทริคอื่นๆ แทนได้ เพื่อให้ประสิทธิภาพดีขึ้น อาจจะไม่ดีที่สุด แต่ development cost ไม่สูงเกินไป เช่นการทำ caching เป็นต้น&lt;&#x2F;p&gt;
&lt;p&gt;อย่างไรก็ตามบทความนี้เป็นเพียงหนึ่งวิธีการที่สามารถเพิ่มประสิทธิภาพของ SPA การปรับปรุงควรคำนึงถึงในหลายๆ ปัจจัย เช่น ต้นทุน ทีม หรือฝั่ง business เป็นต้น&lt;&#x2F;p&gt;
&lt;p&gt;Enjoy coding...&lt;&#x2F;p&gt;
&lt;p&gt;ความตั้งใจเดิมอยากเขียนไปให้ถึง Server Component ใน React 18 แต่เอาไว้ยกยอดไป Blog หน้า ถ้ามีใครมีประเด็นอะไรอยากเสริมหรือแนะนำ ผมยินดีเลยครับ สำหรับวันนี้ลาไปก่อน สวัสดีครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;acknowledgement&quot;&gt;Acknowledgement&lt;a class=&quot;zola-anchor&quot; href=&quot;#acknowledgement&quot; aria-label=&quot;Anchor link for: acknowledgement&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;สุดท้ายนี้ (จริงๆแล้วน้า) ขอขอบคุณ&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.dotnetthailand.com&#x2F;&quot;&gt;ทีมงาน Admin .NET Thailand&lt;&#x2F;a&gt; มากๆ ที่ช่วยรีวิวและแนะนำบทความนี้จนสามารถเผยแพร่ออกไปได้&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>มาเขียน Notion Formula with Confidence ด้วย TDD กัน (แจก Formula Thousand Comma ด้วยนะ)</title>
		<published>2021-06-26T00:00:00+00:00</published>
		<updated>2021-06-26T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/tdd-formula-in-notion-thousand-comma/" type="text/html"/>
		<id>https://thadaw.com/posts/tdd-formula-in-notion-thousand-comma/</id>
		<content type="html">&lt;p&gt;สวัสดีครับ วันนี้ผมมาแชร์เทคนิคการเขียน สูตรแบบ ยังไงก็ไม่พลาดแน่ๆ กันครับ เทคนิคที่ใช้ TDD (Test-Driven Development) คือ โดยผมประยุกต์ใช้ใน Notion โดย&lt;&#x2F;p&gt;
&lt;p&gt;ในตัวอย่างนี้จะใช้สูตรการใส่ comma เลขหลักพันนะครับ มาเริ่มกันเลย!&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;การสร้าง Table มา&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;กำหนด Column&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Number = คือค่าตั้งต้น&lt;&#x2F;li&gt;
&lt;li&gt;Output = สูตรของเรา&lt;&#x2F;li&gt;
&lt;li&gt;Expected = สิ่งที่เราอยากให้เป็น คำตอบที่ถูกต้อง&lt;&#x2F;li&gt;
&lt;li&gt;Tester = สูตรง่ายๆ สำหรับเช็คว่า Output กับ Expected เท่ากันมั้ย&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เราจะเริ่มจากให้ Pass บางเคสก่อน (เอาจริงๆ ต้องเริ่มจาก Fail ทุกเคส แต่นี้ขอข้ามขั้นตอนนั้นไป)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;tdd-formula-in-notion-thousand-comma&#x2F;01-fail-test.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;จากนั้น เราจะค่อยๆ ปรับแก้สูตรไปเรื่อยๆ จนผ่านครบทุกเคสครับ&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;thousand-comma-formula&quot;&gt;Thousand Comma Formula&lt;a class=&quot;zola-anchor&quot; href=&quot;#thousand-comma-formula&quot; aria-label=&quot;Anchor link for: thousand-comma-formula&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;div class=&quot;word-wrap&quot;&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;empty&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;prop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Number&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;concat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;if&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;round&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;prop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Number&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;concat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;format&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;floor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;round&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;prop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Number&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;,&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;if&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;mod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;round&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;prop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Number&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;concat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;format&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;floor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;mod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;round&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;prop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Number&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;,&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;if&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;mod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;mod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;round&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;prop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Number&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;00&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;if&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;mod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;mod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;round&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;prop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Number&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;100&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;0&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;format&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;mod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;mod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;round&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;prop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Number&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;format&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;mod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;round&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;prop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Number&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;tester-formula&quot;&gt;Tester Formula&lt;a class=&quot;zola-anchor&quot; href=&quot;#tester-formula&quot; aria-label=&quot;Anchor link for: tester-formula&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;div class=&quot;word-wrap&quot;&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;prop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Output&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-ts&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;prop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Expected&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;✅ PASS&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;❌ FAILED&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;finally-all-test-pass&quot;&gt;Finally, All Test Pass&lt;a class=&quot;zola-anchor&quot; href=&quot;#finally-all-test-pass&quot; aria-label=&quot;Anchor link for: finally-all-test-pass&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;tdd-formula-in-notion-thousand-comma&#x2F;02-pass-test.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;download-tdd-template-with-thousand-comma&quot;&gt;Download TDD Template with Thousand Comma&lt;a class=&quot;zola-anchor&quot; href=&quot;#download-tdd-template-with-thousand-comma&quot; aria-label=&quot;Anchor link for: download-tdd-template-with-thousand-comma&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;https:&#x2F;&#x2F;www.notion.so&#x2F;TDD-Formula-Notion-using-Comma-Thousand-as-a-case-study-80199bc04990423c8e250e7d20fd8f6b&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ทำ Task Management ด้วย Template My Things ( Fully inspired by Things 3 Application )</title>
		<published>2021-05-02T00:00:00+00:00</published>
		<updated>2021-05-02T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/notion-template-my-things/" type="text/html"/>
		<id>https://thadaw.com/posts/notion-template-my-things/</id>
		<content type="html">&lt;p&gt;สวัสดีครับวันนี้มาแชร์ Template: My Things  📥 ( Fully inspired by &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;culturedcode.com&#x2F;things&#x2F;&quot;&gt;Things 3&lt;&#x2F;a&gt; Application)&lt;&#x2F;p&gt;
&lt;p&gt;ผมใช้ Notion มาแล้ว 2 ปี ปรับ process การทำงานมาหลายแบบมาก ดู August Bradley แล้วก็ทำตามแล้วไม่ใช่ตัวเอง เลยปรับหลายๆ หลักการทั้ง GTD, แอพ Things 3 ปรับ workflow ต่างๆ ให้ไม่ยุ่งยาก ใช้งานได้ ไม่มีปัญหาบน มือถือด้วย&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;notion-template-my-things&#x2F;home-page.jpg&quot; alt=&quot;home page&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Key Concept คือ เน้นใช้ง่าย ไม่ทำให้กดดันตัวเอง ไม่ต้อง Strict เกินไปแบบ Time Block แต่ต้องเกิดประโยชน์ที่สุด&lt;&#x2F;p&gt;
&lt;p&gt;เป็น Template สำหรับ Todo การจัดการรายการที่ต้องทำ + สิ่งที่อยากทำ (จากนี้ขอเรียกว่า todo ) ช่วยให้ focus กับรายการสิ่งที่อยากทำและต้องทำมากขึ้น และยืดหยุ่น โดยมีจุดเด่น คือ&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;😀 Separation of Concern: ไม่แสดง todo ทั้งหมดในหน้าเดียว แต่จะแยกตามวันเวลา หมวดหมู่  (Area) เพื่อลดความล้า และเหนื่อยในการรีวิว todo จำนวนมาก หรืออาจจะทำให้ท้อได้&lt;&#x2F;li&gt;
&lt;li&gt;📥 Inbox System: เมื่อเราคิดอะไรได้ เราสามารถโยน todo นั้นไปจัดหมวดหมู่ว่าอยู่ประเภทไหน Dealine วันไหนได้อีกที&lt;&#x2F;li&gt;
&lt;li&gt;⭐️Today page: สำหรับการเลือก todo ที่วางแผนจะทำวันนี้ โดยสามารถระบุเวลาที่คาดว่าจะทำได้ มี 5 ช่วงเวลา wake up, morning, afternoon, evening, bedtime
&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;notion-template-my-things&#x2F;today-page.jpg&quot; alt=&quot;today page&quot; &#x2F;&gt;&lt;&#x2F;li&gt;
&lt;li&gt;หน้า ⭐️ Today Page จะมี Template สำหรับจะทำ todos ให้เผื่อนึกไม่ออกว่าควรจะทำอะไรเช่น Bedtime มีอ่านหนังสือ ทาครีมบำรุง เป็นต้น&lt;&#x2F;li&gt;
&lt;li&gt;🗓Upcoming page: สำหรับแสดง todo ที่มี Due Date หรือ Deadline ไว้แล้ว โดยเรียงจากเร็วที่สุดก่อน
&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;notion-template-my-things&#x2F;upcoming-page.jpg&quot; alt=&quot;upcoming&quot; &#x2F;&gt;&lt;&#x2F;li&gt;
&lt;li&gt;🟩 Anytime page: สำหรับ todo ที่ยังไม่ลงเวลา deadline&lt;&#x2F;li&gt;
&lt;li&gt;🗃Somday:  สำหรับ todo ที่จะไม่ทำในเร็วๆ นี้&lt;&#x2F;li&gt;
&lt;li&gt;📗Logbook: สำหรับ todo ที่ทำเสร็จแล้ว โดยเรียงจากวันที่อัพเดทล่าสุด (เมื่อเราทำ todo เสร็จ จะมาอยู่หน้านี้เอง ) สำหรับ review ว่าเราทำอะไรไปแล้วบ้าง&lt;&#x2F;li&gt;
&lt;li&gt;🗑 Trash : ก็ตามชื่อเลย&lt;&#x2F;li&gt;
&lt;li&gt;ใช้ประโยชน์จาก แทบ Navigation ด้านซ้ายในการเปลี่ยนหน้าไปมา เพราะรู้สึกว่า มาใส่ทุกอย่างในหน้าเดียว แล้วกดมันให้ใช้งานยาก&lt;&#x2F;li&gt;
&lt;li&gt;ส่วน Calendar กับ Timeline ก็ตามชื่อเลยครับ&lt;&#x2F;li&gt;
&lt;li&gt;การใช้ Field Hide จะใช้กับ Linked Database ที่ต้องเอานำ todo ไปใส่ เพื่อย้ายตำแหน่งของ todo ไม่มีผลอะไร ของข้อมูล หลักๆ ทำให้ดู Clean ขึ้น ใช้เมนู Data Management ของหน้า  📥 Inbox เพื่อซ่อน todo&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;withiiaich&quot;&gt;วิธีใช้&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiiaich&quot; aria-label=&quot;Anchor link for: withiiaich&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;การใช้งานดูทั่วจะไปจะใช้หน้า Today เป็นหลัก เพื่อดูว่าควรทำอะไรเวลาไหน&lt;&#x2F;li&gt;
&lt;li&gt;การสร้าง todo ใหม่
&lt;ul&gt;
&lt;li&gt;สามารถสร้าง todo ปกติ หรือ แทรกใน database ก็ได้&lt;&#x2F;li&gt;
&lt;li&gt;สามารถทำได้ทุกหน้า แต่แนะนำให้สร้างที่ inbox หรือ today จะสะดวกกว่า&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;การย้าย todo หรือ เปลี่ยน หมวดหมู่(Area)
&lt;ul&gt;
&lt;li&gt;สามารถลากจาก หน้าใดๆ ไป หน้าอื่นๆ ได้เลยครับ แต่ต้องลากใส่ database block จะนะครับ เพราะแต่ละ database block จะเป็น link ไปยัง database ตัวจริงแล้ว filter ออกมา ดังนั้น เมื่อลากเข้าไปแล้ว มันก็จะตั้งค่า field  อัตโนมัติ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;database&quot;&gt;Database&lt;a class=&quot;zola-anchor&quot; href=&quot;#database&quot; aria-label=&quot;Anchor link for: database&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ใช้ Database 1 อัน เพื่อให้ง่ายต่อการจัดการ และใช้งาน ลดความซ้ำซ้อน การออกแบบทั้งหมดเป็นการ Filter ทั้งหมด โดยมี Field ดังนี้&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Done: สำหรับ Mark ว่าทำ todo เสร็จ&lt;&#x2F;li&gt;
&lt;li&gt;Due Date: ก็วันที่จะทำ&lt;&#x2F;li&gt;
&lt;li&gt;Area: เป็นหมวดหมู่ของ todo ถ้าไม่มี Area จะอยู่ใน Inbox&lt;&#x2F;li&gt;
&lt;li&gt;Archive: ให้เลือก Someday หรือ อาจจะใส่อย่างอื่นก็ได้&lt;&#x2F;li&gt;
&lt;li&gt;Time: เป็นตัวเลือกว่าจะทำงานในวันนี้ ถ้าเลือกอย่างใดอย่างหนึ่งจะอยู่ในหน้า Today แต่ถ้าไม่เลือกจะอยู่ใน Anytime หรือ Upcoming (ถ้า Upcoming จะมี Due Date)&lt;&#x2F;li&gt;
&lt;li&gt;โดยเลือกได้ 5 ช่วงเวลาว่าจะทำ Task ช่วงเวลาไหน  wake up, morning, afternoon, evening, bedtime&lt;&#x2F;li&gt;
&lt;li&gt;Tags: เป็นข้อมูลเพิ่มเติม อยากใส่อะไรก็ได้&lt;&#x2F;li&gt;
&lt;li&gt;Urgent: มี 5 Min คือ งานที่ทำเสร็จภายใน 5 นาที ถ้าว่าง ควรทำทันที และ With in today คือ todo  ที่ยืดหยุ่นทำตอนไหนก็ได้ แต่ควรจะเสร็จภายในวันนั้น&lt;&#x2F;li&gt;
&lt;li&gt;Priority: มี important ก็คืองานสำคัญครับ แต่อาจจะไม่เร่งด่วน&lt;&#x2F;li&gt;
&lt;li&gt;Hide: เอาไว้ซ่อนครับ เพื่อความสวยงาม&lt;&#x2F;li&gt;
&lt;li&gt;Last Update: เอาไว้แสดงในหน้า Logbook ครับ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;esrimeruue-ng-things-3&quot;&gt;เสริมเรื่อง Things 3&lt;a class=&quot;zola-anchor&quot; href=&quot;#esrimeruue-ng-things-3&quot; aria-label=&quot;Anchor link for: esrimeruue-ng-things-3&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ถ้าใครอยู่ในวงการนี้ คงน่าจะรู้จักแอพ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;culturedcode.com&#x2F;things&#x2F;&quot;&gt;things 3&lt;&#x2F;a&gt; นะครับ เป็นแอพที่ขายขาดรอบเดียว ไม่มีจ่ายรายเดือนเหมือน Notion ถือว่าดังมากๆ ในเรื่องของ feature ที่เป็นเอกลักษณ์มากๆ และสามารถประยุกได้หลากหลาย&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าใครนึกแนวทางการใช้งานไม่ออก แนะนำให้ดูคลิปสอน Things 3 นะครับ เท่าที่ดูยังไม่มีคนไทยมารีวิว จะเห็นภาพมาก&lt;&#x2F;p&gt;
&lt;p&gt;สุดท้ายนี้ ลองนำไปประยุกต์ใช้งานให้เข้ากับตัวเองดูนะครับ ชอบไม่ชอบยังไงก็บอกได้ครับ หรือใครมีคำถามอะไรก็ยินดีเลยครับ  ขอบคุณที่อ่านจนจบ จริงๆ ที่ Template ที่ทำไว้เยอะ แต่ยังไม่ได้เอามาแบ่งปันกัน วันนี้ถือว่าได้มาแชร์กัน สวัสดีครับ&lt;&#x2F;p&gt;
&lt;p&gt;Download Template
http:&#x2F;&#x2F;bit.ly&#x2F;mildthada-notion-my-things&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Cross published at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.facebook.com&#x2F;groups&#x2F;notionthai&#x2F;posts&#x2F;369652924407139&quot;&gt;Notion Thailand FB Group&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธีการรัน JavaScript ข้างนอก Bundle ของ Webpack และการเรียกใช้ jQuery ภายใน Webpack</title>
		<published>2019-10-14T00:00:00+00:00</published>
		<updated>2019-10-14T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/running-in-line-vanilla-javascript-from-webpack-th/" type="text/html"/>
		<id>https://thadaw.com/posts/running-in-line-vanilla-javascript-from-webpack-th/</id>
		<content type="html">&lt;p&gt;สวัสดีครับ วันนี้ผมจะมาแบ่งปันเรื่องการตั้งค่าการใช้งาน Webpack เบื้องต้น และน่าจะเป็นคำถามและข้อสงสัยสำหรับคนที่หัดใช้ครับ&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;หมายเหตุ: ณ วันที่เขียน Blog อ้างอิงจาก Webpack 4&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;อย่างที่เราทราบกันดีว่า &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;webpack.js.org&#x2F;&quot;&gt;Webpack&lt;&#x2F;a&gt; ถูกใช้กันอย่างมากใน Library พัฒนาเว็บไซต์ที่ใช้ Javascript เป็นหลัก อย่างเช่นเครื่องมือดังๆ อย่าง React, Angular หรือ Vue ก็ตาม หรือหลายๆ เว็บก็ใช้งานเยอะมาก ซึ่งเมื่อตั้งค่าของ Webpack แล้ว เราก็แทบไม่ต้องไปยุ่งกับมันอีก แต่ตอนตั้งค่าครั้งแรกนี่สิ อาจจะเหนื่อยหน่อยสำหรับบางคน&lt;&#x2F;p&gt;
&lt;p&gt;อ่ะ เข้าเรื่องกัน&lt;&#x2F;p&gt;
&lt;h2 id=&quot;webpack-khuue&quot;&gt;Webpack คือ&lt;a class=&quot;zola-anchor&quot; href=&quot;#webpack-khuue&quot; aria-label=&quot;Anchor link for: webpack-khuue&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Webpack พูดง่ายๆ ก็คือการที่รวมโค๊ดเราที่เป็นหลายๆ ไฟล์ ซึ่งจัดเรียงการให้สามารถ Maintainance ได้ง่าย มารวมกันใน 1 Bundle หรือ หลาย Bundle ก็ได้ (ซึ่ง Bundle ก็คือไฟล์ JS ไฟล์ 1 ไฟล์นั้นเอง) เพื่อให้ง่ายต่อการนำไปใช้ และจัดการ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;running-in-line-vanilla-javascript-from-webpack-th&#x2F;2019-10-14-running-in-line-vanilla-javascript-from-webpack-2.png&quot; alt=&quot;Webpack Diagram from https:&#x2F;&#x2F;webpack.js.org&#x2F;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;หลายๆ คนอาจจะสงสัยว่า ในเมื่อ React ก็มี &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;facebook&#x2F;create-react-app&quot;&gt;create-react-app&lt;&#x2F;a&gt; หรือเครื่องมืออื่นที่สามารถสร้างเว็บได้เลย โดยไม่ต้องตั้งค่า Webpack อะไรเลย แล้วเมื่อไหร่เราควรจะใช้ Webpack&lt;&#x2F;p&gt;
&lt;h2 id=&quot;emuue-aihreraakhwrcchaaich-webpack&quot;&gt;เมื่อไหร่เราควรจะใช้ Webpack&lt;a class=&quot;zola-anchor&quot; href=&quot;#emuue-aihreraakhwrcchaaich-webpack&quot; aria-label=&quot;Anchor link for: emuue-aihreraakhwrcchaaich-webpack&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;คำตอบคือ แล้วแต่เราเลย ถ้าคิดว่าไม่ต้องใช้ก็ไม่ต้องใช้ 555+ ตาม Style เวลาคนชอบพูดถึง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;redux.js.org&#x2F;&quot;&gt;Redux&lt;&#x2F;a&gt; ชอบมาก คือ &lt;strong&gt;คุณไม่จำต้องใช้ Redux หากไม่รู้ว่าทำไมถึงต้องใช้&lt;&#x2F;strong&gt; ผมก็คงตอบเหมือนกันกับ Webpack&lt;&#x2F;p&gt;
&lt;p&gt;แต่ในกรณีนี้ผมตั้งค่า Webpack เนื่องจาก&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;จะมีการใช้ Javascript ES2015 (ES6) และสูงขึ้นไป ในที่นี้จัดการโดย &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;babeljs.io&#x2F;&quot;&gt;Babel&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;จะมีการใช้ React แบบบางส่วน บางโมดูลเท่านั้น&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ที่นี้ แล้วถ้าเราจะเขียน JS โดยสั่งควบคุม DOM หรือ select DOM ผ่าน JS ที่อยู่ใน Bundle มันก็ทำปกติ ขอเล่าการใช้ประโยชน์ของ Webpack ใน React App กันนะครับ ถ้าเข้าใจตรงนี้ ก็จะเห็นภาพมากขึ้น&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;React จะมีไฟล์ &lt;code&gt;index.html&lt;&#x2F;code&gt; ซึ่งเป็น Template หลักในการรันแอพ React&lt;&#x2F;li&gt;
&lt;li&gt;ซึ่งในไฟล์ &lt;code&gt;index.html&lt;&#x2F;code&gt; แล้วจะมี Tag &lt;code&gt;&amp;lt;div id=&quot;root&quot;&amp;gt;&amp;lt;&#x2F;div&amp;gt;&lt;&#x2F;code&gt; ซึ่งเป็นตำแหน่งสำหรับให้ React App ทำงาน&lt;&#x2F;li&gt;
&lt;li&gt;จากนั้น React จะเขียน config ของ Webpack ให้ compile โค๊ด React ทั้งหมดลงไฟล์ JS 1 ไฟล์ (หรือ หลายไฟล์ แล้วแต่ออกแบบ) ซึ่ง 1 ไฟล์นี้แหละ เค้าเรียกว่า Bundle ของ Webpack&lt;&#x2F;li&gt;
&lt;li&gt;จากนั้น React ก็จะมีการเขียนโค๊ดให้รันเจ้า React ตรง &lt;code&gt;root&lt;&#x2F;code&gt; นั้นแหละ ที่เราเขียนไว้ใน &lt;code&gt;index.html&lt;&#x2F;code&gt; ถ้าจำกันได้เวลาเราใช้ &lt;code&gt;create-react-app&lt;&#x2F;code&gt; จะสั่ง Render React App ที่ id &lt;code&gt;root&lt;&#x2F;code&gt; ในไฟล์แรกที่เราเขียนคือ &lt;code&gt;index.js&lt;&#x2F;code&gt; ตามข้างล่างเลย&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;render&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;App&lt;&#x2F;span&gt; &#x2F;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-variable z-dom z-ts&quot;&gt;document&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;getElementById&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;root&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;นี่คือประโยชน์อย่างนึงของ Webpack เห็นมั้ยครับ จากตัวอย่างข้างบนคือ เราเรียกออกมาข้างนอก Bundle แต่จะเรียก function ใน  Bundle ล่ะ ทำยังไง&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งหน้าตาที่เราอยากคือ ประมาณนี้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;html&quot; class=&quot;language-html z-code&quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dist&#x2F;index.js&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-end z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;text&#x2F;javascript&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    &lt;span class=&quot;z-source z-js z-embedded z-html&quot;&gt;&lt;span class=&quot;z-source z-js&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-js&quot;&gt;&lt;span class=&quot;z-variable z-function z-js&quot;&gt;hello&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-js&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-js&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-js&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-js&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-js&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Webpack&lt;span class=&quot;z-punctuation z-definition z-string z-end z-js&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-js&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-js&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-source z-js z-embedded z-html&quot;&gt;&lt;span class=&quot;z-source z-js&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-end z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;คือ function &lt;code&gt;hello&lt;&#x2F;code&gt; ซึ่งในอยู่ใน Bundle ของ Webpack ที่ชื่อ &lt;code&gt;dist&#x2F;index.js&lt;&#x2F;code&gt; ที่นี่มาเข้าเรื่องของเรากันคือ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;withiikaarran-javascript-khaangn-k-bundle-kh-ng-webpack&quot;&gt;วิธีการรัน JavaScript ข้างนอก Bundle ของ Webpack&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiikaarran-javascript-khaangn-k-bundle-kh-ng-webpack&quot; aria-label=&quot;Anchor link for: withiikaarran-javascript-khaangn-k-bundle-kh-ng-webpack&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Webpack ค่อนข้างเรียนรู้ยากสำหรับคนที่เพิ่งเริ่มต้น ซึ่งเท่าที่ลองศึกษาดู ก็มีคนพูดวิธีให้ไปแก้ไข config ใน &lt;code&gt;webpack.config.js&lt;&#x2F;code&gt; อย่าง&lt;a href=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;running-in-line-vanilla-javascript-from-webpack-th&#x2F;(https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;34357489&#x2F;calling-webpacked-code-from-outside-html-script-tag)&quot;&gt;โพสนี้&lt;&#x2F;a&gt;
อย่างไรก็ตาม เรามาลองวิธีนี้กัน&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;ตั้งค่า &lt;code&gt;webpack.config.js&lt;&#x2F;code&gt; ตามโค๊ดข้างล่างตามนี้ คือใช้การตั้งค่าทั่วๆ ไป (ไม่ลงรายละเอียดตรงนี้นะครับ)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;require&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;path&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-support z-type z-object z-module z-ts&quot;&gt;module&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-object z-module z-ts&quot;&gt;exports&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;entry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;.&#x2F;src&#x2F;index.js&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-promise z-ts&quot;&gt;resolve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-object z-node z-ts&quot;&gt;__dirname&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;src&#x2F;dist&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;filename&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;index.js&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;module&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;rules&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-backslash z-regexp&quot;&gt;\.&lt;&#x2F;span&gt;m&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;?&lt;&#x2F;span&gt;js&lt;span class=&quot;z-keyword z-control z-anchor z-regexp&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;exclude&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-regexp&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-regexp&quot;&gt;(&lt;&#x2F;span&gt;node_modules&lt;span class=&quot;z-keyword z-operator z-or z-regexp&quot;&gt;|&lt;&#x2F;span&gt;bower_components&lt;span class=&quot;z-punctuation z-definition z-group z-regexp&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;use&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;          &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;loader&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;babel-loader&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;          &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;options&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;            &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;presets&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;@babel&#x2F;preset-env&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;          &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;แล้วในไฟล์ &lt;code&gt;src&#x2F;index.js&lt;&#x2F;code&gt; เราก็เขียน JS กันและมีตัวอย่างการเรียกใช้ &lt;code&gt;JQuery&lt;&#x2F;code&gt; ซึ่งหลักการก็คือเอา function ไปใส่ไว้ใน &lt;code&gt;window&lt;&#x2F;code&gt; ซึ่งเวลานำ Bundle นี้ไปใช้งานก็จะสามารถเข้าถึง function นี้ได้&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-support z-variable z-dom z-ts&quot;&gt;window&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;$&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-variable z-dom z-ts&quot;&gt;window&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;jQuery&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;require&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;jquery&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;hello&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Hello &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;#hello-text&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;html&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Hello &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;, see also in &amp;#39;Console&amp;#39;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;window&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-support z-variable z-dom z-ts&quot;&gt;window&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;EntryPoint&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;hello&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-dom z-ts&quot;&gt;window&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;โดยผมสั่งให้พิมพ์ parameter และสั่งแก้ DOM ชื่อ &lt;code&gt;hello-text&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;ต่อไปก็คือเขียนไฟล์ HTML โดยไฟล์ bundle คือ &lt;code&gt;dist&#x2F;index.js&lt;&#x2F;code&gt; เราก็สามารถเรียกผ่านตัวแปร &lt;code&gt;EntryPoint&lt;&#x2F;code&gt; ได้เลย หรือตัวแปรอื่นๆ ก็ได้ โดยหน้าตาก็ประมาณนี้&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;html&quot; class=&quot;language-html z-code&quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-tag z-block z-any z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-block z-any z-html&quot;&gt;h1&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-id z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-id z-html&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-meta z-toc-list z-id z-html&quot;&gt;hello-text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-block z-any z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-block z-any z-html&quot;&gt;h1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dist&#x2F;index.js&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-end z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;text&#x2F;javascript&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;    &lt;span class=&quot;z-source z-js z-embedded z-html&quot;&gt;&lt;span class=&quot;z-source z-js&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-method z-js&quot;&gt;&lt;span class=&quot;z-support z-class z-js&quot;&gt;EntryPoint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-js&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-js&quot;&gt;hello&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-js&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-js&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-js&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-js&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-js&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Webpack&lt;span class=&quot;z-punctuation z-definition z-string z-end z-js&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-js&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-js&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-source z-js z-embedded z-html&quot;&gt;&lt;span class=&quot;z-source z-js&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-end z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;นี้คือตัวอย่างการทำงาน&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;running-in-line-vanilla-javascript-from-webpack-th&#x2F;2019-10-14-running-in-line-vanilla-javascript-from-webpack.png&quot; alt=&quot;webpack&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;เพื่อเข้าใจมากขึ้นสามารถเข้าไปดู source ได้ที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;webpack-with-vanilla-js&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;webpack-with-vanilla-js&lt;&#x2F;a&gt; ได้เลยครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>React Design Patterns</title>
		<published>2019-04-11T00:00:00+00:00</published>
		<updated>2019-04-11T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/react-design-patterns/" type="text/html"/>
		<id>https://thadaw.com/posts/react-design-patterns/</id>
		<content type="html">&lt;p&gt;Hi everyone, here is not getting started guide for writing React. You should have some basic of React such as &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;docs&#x2F;hello-world.html&quot;&gt;basic concept of React&lt;&#x2F;a&gt; and practical &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;tutorial&#x2F;tutorial.html&quot;&gt;React tutorial&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;a class=&quot;zola-anchor&quot; href=&quot;#overview&quot; aria-label=&quot;Anchor link for: overview&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;m following &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;airbnb&#x2F;javascript&#x2F;tree&#x2F;master&#x2F;react&quot;&gt;Airbnb style guide&lt;&#x2F;a&gt; and using  react in pattern books for references https:&#x2F;&#x2F;github.com&#x2F;krasimir&#x2F;react-in-patterns, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vasanthk&#x2F;react-bits&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;vasanthk&#x2F;react-bits&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;designing-react-web-application&quot;&gt;Designing React Web Application&lt;a class=&quot;zola-anchor&quot; href=&quot;#designing-react-web-application&quot; aria-label=&quot;Anchor link for: designing-react-web-application&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Nowadays, we have many approaches to design the composition of react component.&lt;&#x2F;p&gt;
&lt;p&gt;Here is one of approaches to design&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Preparation&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Use Airbnb style guide for consistency code style&lt;&#x2F;li&gt;
&lt;li&gt;Use popular React boilerplate (&lt;code&gt;create-react-app&lt;&#x2F;code&gt;) for reducing complexity to manage build tools such as webpack, babel, etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;Basic Design&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In React documentation describes &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;docs&#x2F;thinking-in-react.html&quot;&gt;Thinking in React&lt;&#x2F;a&gt;  for explaining how to design react component and how they compose each others. However, when I &#x27;ve getting started with React, I realize the component design thinking is most important thing for designing react application. In a React application, it will be at least one component, or can be divided into child component which should work with the parent one.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Start with a few React component for reducing the complexity in state management.&lt;&#x2F;li&gt;
&lt;li&gt;Break the code down to component when necessary, if it feel easier.&lt;&#x2F;li&gt;
&lt;li&gt;The component can break into 2 parts: &lt;strong&gt;Container Component&lt;&#x2F;strong&gt; and &lt;strong&gt;Presentational Component&lt;&#x2F;strong&gt;, when necessary.
&lt;ol&gt;
&lt;li&gt;Container Component&lt;&#x2F;li&gt;
&lt;li&gt;Presentational Component&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;Advanced Design: Reusable Components&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Break the code down to component if you want to reuse the components.&lt;&#x2F;li&gt;
&lt;li&gt;Use High-order Component when necessary.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;composing-components&quot;&gt;Composing components&lt;a class=&quot;zola-anchor&quot; href=&quot;#composing-components&quot; aria-label=&quot;Anchor link for: composing-components&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;Passing a child as a prop&lt;&#x2F;li&gt;
&lt;li&gt;Passing state through the props&lt;&#x2F;li&gt;
&lt;li&gt;Using top component for storing state&lt;&#x2F;li&gt;
&lt;li&gt;Using simple state management library for small application
&lt;ol&gt;
&lt;li&gt;Honorable mention libraries: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gunn&#x2F;pure-store&quot;&gt;pure-store&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jamiebuilds&#x2F;unstated&quot;&gt;unstated&lt;&#x2F;a&gt; and &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;developit&#x2F;unistore&quot;&gt;unistore&lt;&#x2F;a&gt;other approaches are shown at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;GantMan&#x2F;ReactStateMuseum&quot;&gt;React State Museum&lt;&#x2F;a&gt; which good place for reviewing react state management library.&lt;&#x2F;li&gt;
&lt;li&gt;I&#x27;m interesting in &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mobxjs&#x2F;mobx&quot;&gt;mobx&lt;&#x2F;a&gt; approaches for small application&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Using  &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;reduxjs&#x2F;redux&quot;&gt;Redux&lt;&#x2F;a&gt; , &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mobxjs&#x2F;mobx&quot;&gt;mobx&lt;&#x2F;a&gt; for big application&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Alternative, you can use MVC approach if you familiar, however, in my opinion using MVC on react.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;design-patterns-and-techniques&quot;&gt;Design Patterns and Techniques&lt;a class=&quot;zola-anchor&quot; href=&quot;#design-patterns-and-techniques&quot; aria-label=&quot;Anchor link for: design-patterns-and-techniques&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;component-organization-templates-patterns&quot;&gt;Component Organization Templates &amp;amp; Patterns&lt;a class=&quot;zola-anchor&quot; href=&quot;#component-organization-templates-patterns&quot; aria-label=&quot;Anchor link for: component-organization-templates-patterns&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;full-feature-stateful-component&quot;&gt;Full Feature (Stateful Component)&lt;a class=&quot;zola-anchor&quot; href=&quot;#full-feature-stateful-component&quot; aria-label=&quot;Anchor link for: full-feature-stateful-component&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;Person&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-ts&quot;&gt;Component&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-storage z-type z-ts&quot;&gt;constructor&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;props&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-super z-ts&quot;&gt;super&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;props&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;state&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;smiling&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-false z-ts&quot;&gt;false&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;handleClick&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;setState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;smiling&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;state&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;smiling&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;componentWillMount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; add event listeners (Flux Store, WebSocket, document, etc.)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;componentDidMount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; React.getDOMNode()&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;componentWillUnmount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; remove event listeners (Flux Store, WebSocket, document, etc.)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-property z-ts&quot;&gt;get&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;smilingMessage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;state&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;smiling&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;is smiling&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;render&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;div&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;onClick&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;this.&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;handleClick&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;        &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;this&lt;&#x2F;span&gt;.&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;props&lt;&#x2F;span&gt;.&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;this&lt;&#x2F;span&gt;.&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;smilingMessage&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;Person&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;defaultProps&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Guest&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;Person&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;propTypes&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;PropTypes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;string&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ref: https:&#x2F;&#x2F;github.com&#x2F;chantastic&#x2F;react-patterns#component-organization&lt;&#x2F;p&gt;
&lt;h4 id=&quot;stateless-component&quot;&gt;Stateless Component&lt;a class=&quot;zola-anchor&quot; href=&quot;#stateless-component&quot; aria-label=&quot;Anchor link for: stateless-component&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;StatelessComponent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;This&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;is&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Stateless&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Component&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;stateless-component-with-props&quot;&gt;Stateless Component with props&lt;a class=&quot;zola-anchor&quot; href=&quot;#stateless-component-with-props&quot; aria-label=&quot;Anchor link for: stateless-component-with-props&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;StatelessComponent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;data&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Container Component&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can split our component into 2 types: Container component, Presentational component&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; CommentList.js&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;CommentList&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-ts&quot;&gt;Component&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;render&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;        &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;this&lt;&#x2F;span&gt;.&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;props&lt;&#x2F;span&gt;.&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;comments&lt;&#x2F;span&gt;.&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;map&lt;&#x2F;span&gt;((&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;body&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;author&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;) &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;          return &amp;lt;li&amp;gt;{&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;body&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;—&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;author&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;li&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;        &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;    )&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; CommentListContainer.js&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;CommentListContainer&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-ts&quot;&gt;Component&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;getInitialState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;comments&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;componentDidMount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;ajax&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;url&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;my-comments.json&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;dataType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;json&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;comments&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;setState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;comments&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;comments&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;bind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;render&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;CommentList&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;comments&lt;&#x2F;span&gt;=&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;state&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;comments&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &#x2F;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Read more for &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;krasimir.gitbooks.io&#x2F;react-in-patterns&#x2F;content&#x2F;chapter-06&#x2F;&quot;&gt;Presentational and container components&lt;&#x2F;a&gt;, using ref https:&#x2F;&#x2F;github.com&#x2F;chantastic&#x2F;react-patterns#container-components&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;jsx-rendering&quot;&gt;JSX Rendering&lt;a class=&quot;zola-anchor&quot; href=&quot;#jsx-rendering&quot; aria-label=&quot;Anchor link for: jsx-rendering&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;if&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;isActive&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Message&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;if-else&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;isTrue&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;span&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Rendered&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;when&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;TRUE&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;span&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;span&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Rendered&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;when&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;FALSE&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;span&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Loop items for JSX&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;todos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;text&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Test&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;text&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Write a paper&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;sampleComponent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;        &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;todos&lt;&#x2F;span&gt;.&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;map&lt;&#x2F;span&gt;(&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;todo&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;        	&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;li&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;todo.&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;todo.&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;text&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;li&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;)&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;two-way-binding&quot;&gt;Two way binding&lt;a class=&quot;zola-anchor&quot; href=&quot;#two-way-binding&quot; aria-label=&quot;Anchor link for: two-way-binding&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;App&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-ts&quot;&gt;Component&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;state&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;textbox&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;render&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;input&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;          &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;text&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;          &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;this.state.&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;textbox&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;          &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;(e) =&amp;gt; this.setState({ &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;textbox&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;target&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;value&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;        &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;state&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;textbox&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;    )&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;composing-components-1&quot;&gt;Composing components&lt;a class=&quot;zola-anchor&quot; href=&quot;#composing-components-1&quot; aria-label=&quot;Anchor link for: composing-components-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;file-structure&quot;&gt;File Structure&lt;a class=&quot;zola-anchor&quot; href=&quot;#file-structure&quot; aria-label=&quot;Anchor link for: file-structure&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Todo Components&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── components
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│   ├── todo
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│      ├── index.jsx
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│      ├── AddTodo.jsx
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│      └── TodoList
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│          ├── index.jsx
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│          └── Todo.jsx
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── app.js
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;└── index.js
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;passing-a-child-as-a-prop&quot;&gt;Passing a child as a prop&lt;a class=&quot;zola-anchor&quot; href=&quot;#passing-a-child-as-a-prop&quot; aria-label=&quot;Anchor link for: passing-a-child-as-a-prop&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Every React component has &lt;code&gt;children&lt;&#x2F;code&gt; props.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;Title&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;h1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Hello&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;there&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;h1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;Header&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;children&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;header&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;title&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;children&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;header&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;App&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Header&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &amp;lt;Title &#x2F;&amp;gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Resting&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;content&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Header&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ref: https:&#x2F;&#x2F;krasimir.gitbooks.io&#x2F;react-in-patterns&#x2F;content&#x2F;chapter-04&#x2F;#passing-a-child-as-a-prop&lt;&#x2F;p&gt;
&lt;h3 id=&quot;passing-state-through-the-props&quot;&gt;Passing state through the props&lt;a class=&quot;zola-anchor&quot; href=&quot;#passing-state-through-the-props&quot; aria-label=&quot;Anchor link for: passing-state-through-the-props&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Counter.jsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;Counter&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-ts&quot;&gt;Component&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;state&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;count&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;handleAdd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;setState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;count&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;state&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;count&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;render&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;CounterView&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;this.state.&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;count&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;onAdd&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;() =&amp;gt; this.handleAdd()&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;CounterView&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; CounterView.jsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;CounterView&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;onAdd&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;Fragment&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;Count&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;button&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;onClick&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;onAdd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Add&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;button&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;Fragment&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;using-top-component-for-storing-state&quot;&gt;Using top component for storing state&lt;a class=&quot;zola-anchor&quot; href=&quot;#using-top-component-for-storing-state&quot; aria-label=&quot;Anchor link for: using-top-component-for-storing-state&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; store.js&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-export z-ts&quot;&gt;export&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-default z-ts&quot;&gt;default&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;root&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;getRoot&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;setRoot&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;root&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-export z-default z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; Counter.jsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;Counter&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-ts&quot;&gt;Component&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-storage z-type z-ts&quot;&gt;constructor&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;props&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-super z-ts&quot;&gt;super&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;props&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;state&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;count&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;store&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;setRoot&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;handleAdd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;setState&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;count&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;state&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;count&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;render&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;CounterView&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;this.state.&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;count&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;CounterView&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; CounterView.jsx&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;CounterView&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameter z-object-binding-pattern z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;value&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-binding-pattern z-object z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;Fragment&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;Count&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-annotation z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-type z-annotation z-ts&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-field z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-property z-ts&quot;&gt;&lt;span class=&quot;z-variable z-object z-property z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-begin z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters z-end z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;button&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;onClick&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;() =&amp;gt; store.getRoot().handleAdd()&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;Add&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;button&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;Fragment&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Thanks for &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;anastue.com&#x2F;&quot;&gt;Anas&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;share-state-between-components&quot;&gt;Share state between components&lt;a class=&quot;zola-anchor&quot; href=&quot;#share-state-between-components&quot; aria-label=&quot;Anchor link for: share-state-between-components&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Design choice:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Small Application: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gunn&#x2F;pure-store&quot;&gt;pure-store&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jamiebuilds&#x2F;unstated&quot;&gt;unstated&lt;&#x2F;a&gt; and &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;developit&#x2F;unistore&quot;&gt;unistore&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Small - Medium Application: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mobxjs&#x2F;mobx&quot;&gt;mobx&lt;&#x2F;a&gt; (Also using &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jamiebuilds&#x2F;unstated&quot;&gt;unstated&lt;&#x2F;a&gt; and &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;developit&#x2F;unistore&quot;&gt;unistore&lt;&#x2F;a&gt; )&lt;&#x2F;li&gt;
&lt;li&gt;Using  &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;reduxjs&#x2F;redux&quot;&gt;Redux&lt;&#x2F;a&gt; , &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mobxjs&#x2F;mobx&quot;&gt;mobx&lt;&#x2F;a&gt; for big application&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Read more how to implement in each state management library in &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;GantMan&#x2F;ReactStateMuseum&quot;&gt;React State Museum&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-to-choose-the-composing-component-pattern&quot;&gt;How to choose the composing component pattern?&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-to-choose-the-composing-component-pattern&quot; aria-label=&quot;Anchor link for: how-to-choose-the-composing-component-pattern&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;style-guide-naming&quot;&gt;Style Guide &amp;amp; Naming&lt;a class=&quot;zola-anchor&quot; href=&quot;#style-guide-naming&quot; aria-label=&quot;Anchor link for: style-guide-naming&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;style-guide&quot;&gt;Style Guide&lt;a class=&quot;zola-anchor&quot; href=&quot;#style-guide&quot; aria-label=&quot;Anchor link for: style-guide&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Read more in &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;airbnb&#x2F;javascript&#x2F;tree&#x2F;master&#x2F;react&quot;&gt;Airbnb&#x27;s Style guide&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;naming-events&quot;&gt;Naming Events&lt;a class=&quot;zola-anchor&quot; href=&quot;#naming-events&quot; aria-label=&quot;Anchor link for: naming-events&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;Owner&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-ts&quot;&gt;extends&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-module z-ts&quot;&gt;React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-ts&quot;&gt;Component&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;handleClick&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; handle click event&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;render&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;div&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;onClick&lt;&#x2F;span&gt;=&lt;span class=&quot;z-meta z-object z-type z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; =&amp;gt; this.&lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;handleClick&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-cast z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-angle z-ts&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Original: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;chantastic&#x2F;react-patterns#naming-events&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;chantastic&#x2F;react-patterns#naming-events&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;other-resources&quot;&gt;Other Resources&lt;a class=&quot;zola-anchor&quot; href=&quot;#other-resources&quot; aria-label=&quot;Anchor link for: other-resources&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Other topics can read in below resources:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;facebook.github.io&#x2F;react&#x2F;contributing&#x2F;design-principles.html&quot;&gt;React Design principles&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;airbnb&#x2F;javascript&#x2F;tree&#x2F;master&#x2F;react&quot;&gt;Airbnb React&#x2F;JSX Style Guide&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;krasimir&#x2F;react-in-patterns&quot;&gt;React in pattern by krasimir&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;planningcenter&#x2F;react-patterns&quot;&gt;React patterns at Planning Center Online&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;reactpatterns.com&#x2F;&quot;&gt;React patterns by Michael Chan&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vasanthk&#x2F;react-bits&quot;&gt;React patterns, techniques, tips and tricks&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;State&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;GantMan&#x2F;ReactStateMuseum&quot;&gt;React State Museum&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;P.S. PR, Suggestions are welcome&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Amazing UI Design Articles</title>
		<published>2019-03-24T00:00:00+00:00</published>
		<updated>2019-03-24T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/amazing-ui-design-articles/" type="text/html"/>
		<id>https://thadaw.com/posts/amazing-ui-design-articles/</id>
		<content type="html">&lt;h2 id=&quot;refactor-ui&quot;&gt;Refactor UI&lt;a class=&quot;zola-anchor&quot; href=&quot;#refactor-ui&quot; aria-label=&quot;Anchor link for: refactor-ui&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;refactoringui.com&#x2F;&quot;&gt;Adam Wathan &amp;amp; Steve Schoger&lt;&#x2F;a&gt;, full stack developer, who are facing the design problem. They shows how amazing way to refactor UI without design skill in thier &quot;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;refactoring-ui&#x2F;7-practical-tips-for-cheating-at-design-40c736799886&quot;&gt;7 Practical Tips for Cheating at Design&lt;&#x2F;a&gt;&quot; article.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;cdn-images-1.medium.com&#x2F;max&#x2F;2600&#x2F;1*KYZikUrx9F02cJU9kpn_gQ.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Another good arcticle from &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;refactoringui.com&#x2F;&quot;&gt;Adam Wathan &amp;amp; Steve Schoger&lt;&#x2F;a&gt; for redesigning application UI in Laravel forum website via their article, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;refactoring-ui&#x2F;redesigning-laravel-io-c47ac495dff0&quot;&gt;Redesigning Laravel.io&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;cdn-images-1.medium.com&#x2F;max&#x2F;2400&#x2F;1*AZkkwzahAr0VpKdJ4OzRNQ.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;design&quot;&gt;Design&lt;a class=&quot;zola-anchor&quot; href=&quot;#design&quot; aria-label=&quot;Anchor link for: design&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Fundamental Design for web via &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;medium.freecodecamp.org&#x2F;before-you-can-master-design-you-must-first-master-the-fundamentals-1981a2af1fda&quot;&gt;Before you can master design, you must first master the fundamentals&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This article talks about 4 fundamentals&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Go back to the basics with type&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Use space to create balance&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Use size to establish visual hierarchy&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Use color to convey meaning&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;ui-ux-animation&quot;&gt;UI&#x2F;UX Animation&lt;a class=&quot;zola-anchor&quot; href=&quot;#ui-ux-animation&quot; aria-label=&quot;Anchor link for: ui-ux-animation&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Other interesting stuff about design&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;cdn-images-1.medium.com&#x2F;max&#x2F;2600&#x2F;1*boQYFGPLtlDof3RRs124bQ.gif&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;https:&#x2F;&#x2F;medium.com&#x2F;ux-in-motion&#x2F;creating-usability-with-motion-the-ux-in-motion-manifesto-a87a4584ddc&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>สิ่งที่ได้รับจากการเรียนวิศวกรรมคอมพิวเตอร์ปริญญาโท</title>
		<published>2019-03-17T00:00:00+00:00</published>
		<updated>2019-03-17T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/what-i-get-from-master-degree/" type="text/html"/>
		<id>https://thadaw.com/posts/what-i-get-from-master-degree/</id>
		<content type="html">&lt;p&gt;สวัสดีคับ ผมชื่อมายด์คับ ห่างหายจากการเขียนบล็อกมานานแสนนานมาก เนื่องจากต้องไปรับราชการทหารอยู่ 6 เดือนระหว่างตอนที่เรียนโทอยู่ครับ วันนี้ก็มีเรื่องเล่ามาแชร์ ให้ฟังคับว่า เป็นอย่างไรบ้างระหว่างการเรียน และได้อะไรมาบ้าง (อาจจะไม่ครบถ้วน ถ้านึกออกจะมาใส่เพิ่มนะครับ) ถือว่าเป็นการแบ่งปันนะคับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;singthiiaidcchaakkaareriiynoth&quot;&gt;สิ่งที่ได้จากการเรียนโท&lt;a class=&quot;zola-anchor&quot; href=&quot;#singthiiaidcchaakkaareriiynoth&quot; aria-label=&quot;Anchor link for: singthiiaidcchaakkaareriiynoth&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;องค์ความรู้ต่างๆ&lt;&#x2F;strong&gt; : แน่นอนครับการเรียนที่สูงขึ้นก็ต้องได้ความรู้ในด้านที่เราสนใจลึกลงไป&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ความสามารถในการเรียนรู้สิ่งใหม่ๆ ด้วยตนเอง&lt;&#x2F;strong&gt;: หลายๆ สิ่งที่เราศึกษาเป็นสิ่งที่ยังไม่มีคนทำทีครับ ดังนั้นเราต้องต่อยอดองค์ความรู้เดิมให้ได้ ถ้ามีไม่พอก็ต้องศึกษาเพิ่ม ถ้ามีผู้รู้ก็ยิ่งดีเลย ถ้าไม่มีใครให้ถามก็ต้องพึ่งตัวเองครับ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ทักษะวิจัย&lt;&#x2F;strong&gt;: ตรงนี้ค่อนข้างยาว ยกไปพูดหัวข้อถัดไปละกันคับ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;การพัฒนาตัวเอง&lt;&#x2F;strong&gt;: ในหลายๆ ด้าน ไม่ว่าการบริหารจัดการเวลา การจัดการตัวเอง การวางแผน ความรับผิดชอบ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ทักษะการสื่อสาร&lt;&#x2F;strong&gt;: ให้คนอื่นเข้าใจ การพูดการนำเสนอ การทำสไลด์&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;thaksawicchay&quot;&gt;ทักษะวิจัย&lt;a class=&quot;zola-anchor&quot; href=&quot;#thaksawicchay&quot; aria-label=&quot;Anchor link for: thaksawicchay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ผมเรียนแบบแผน ก2 ก็คือ มีเรียน lecture ด้วยประมาณ 4-5 วิชา แล้วก็มีวิทยานิพนธ์ด้วย&lt;&#x2F;p&gt;
&lt;p&gt;ทักษะวิจัย เป็นอะไรที่ไม่เคยเข้าใจเลยไม่ว่าจะผ่านการทำโครงงานหรือโปรเจ็คต่างๆมา พอสมควร จนกระทั่งเรียนโทนี่แหละ และเป็นอะไรที่อธิบายได้ยากครับว่ามันเป็นยังไง อารมณ์เหมือนว่าเราต้องเข้าใจถึงโจทย์หรือปัญหา ภาษาทางวิจัยเค้าเรียกว่า problem statement ว่าอะไรคือประเด็นปัญหา แล้วประเด็นปัญหาที่ว่านั่นเป็นปัญหาทางวิศวกรรมคอมพิวเตอร์หรือไม่ ( เกี่ยวข้องกับสาขาที่เรียน ) แล้วเราจะแก้ปัญหาอย่างไร เสนอแนวทางการแก้ปัญหาอย่างไร แล้ววัดผลอะไรบ้าง มีปัจจัยอะไรบ้างที่จะวิเคราะห์ สรุปผลการทดลอง แล้วอะไรคือ contribution สิ่งที่จะเป็นประโยชน์หรือองค์ความรู้ที่เกิดขึ้นมาใหม่ ซึ่งล้อกับวัตถุประสงค์ที่เราตั้งไว้&lt;&#x2F;p&gt;
&lt;p&gt;โดยความคิดเห็นของผมเอง คิดว่ามันเป็นทักษะที่มีประโยชน์ในหลายๆ ด้านเลยครับ สิ่งจริงๆ สิ่งที่ได้จริงจากการเรียนคือไม่ใช่แค่ความรู้ ความชำนาญในเรื่องที่เกี่ยวข้องเท่านั้น แต่ยังสามารถคิดริเริ่มสิ่งใหม่ๆ โดยไม่กลัว และยังสร้างองค์ความรู้ใหม่ และอธิปรายสิ่งที่ที่เกิดขึ้นได้ เพราะว่าบางเหตุการณ์มันก็ไม่ได้เป็นไปตามคาดคับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;occhthykh-ngphm&quot;&gt;โจทย์ของผม&lt;a class=&quot;zola-anchor&quot; href=&quot;#occhthykh-ngphm&quot; aria-label=&quot;Anchor link for: occhthykh-ngphm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;นอกจากปริญญาบัตรและทักษะวิจัย สิ่งที่ผมคาดหวังว่าจะได้จากเรียนคือทักษะที่เกี่ยวข้องกับวิชาชีพ&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;ปริญญาบัตร&lt;&#x2F;li&gt;
&lt;li&gt;เทคโนโลยีที่ใช้ต้องทันสมัย&lt;&#x2F;li&gt;
&lt;li&gt;และสุดท้ายเรื่องที่ทำต้องทันสมัยด้วย&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;singthiiphmtham&quot;&gt;สิ่งที่ผมทำ&lt;a class=&quot;zola-anchor&quot; href=&quot;#singthiiphmtham&quot; aria-label=&quot;Anchor link for: singthiiphmtham&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ก่อนอื่นเลยต้องอธิบายภาพรวมก่อน คือ ผมปรับปรุงประสิทธิภาพฐานข้อมูล opentsdb ให้สามารถ query เร็วกว่าเดิมโดยใช้ cache ของ memcached และตรงกับเงื่อนไขของผมพอดี&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rwmsingthiiaidcchaakkaareriiyn&quot;&gt;รวมสิ่งที่ได้จากการเรียน&lt;a class=&quot;zola-anchor&quot; href=&quot;#rwmsingthiiaidcchaakkaareriiyn&quot; aria-label=&quot;Anchor link for: rwmsingthiiaidcchaakkaareriiyn&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จะเขียนสิ่งที่ได้จากการเรียนโท ออกเป็นบล็อกย่อยๆ ตามหัวข้อข้างล่าง&lt;&#x2F;p&gt;
&lt;h3 id=&quot;related-article&quot;&gt;Related Article&lt;a class=&quot;zola-anchor&quot; href=&quot;#related-article&quot; aria-label=&quot;Anchor link for: related-article&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;การวาดกราฟจากข้อมูลจำนวนมากด้วย Numpy (Plot graph with numpy )&lt;&#x2F;li&gt;
&lt;li&gt;automate test ด้วย python ซึ่งไปรัน docker อีกทีนึง&lt;&#x2F;li&gt;
&lt;li&gt;เขียนโปรแกรม linux บน Windows (MacOS ก็ได้ คอนเซ็ปเดียวกัน) แบบ Seamless คือทำ two-way sync โดยใช้ docker, unison, intellji + script นิดหน่อย&lt;&#x2F;li&gt;
&lt;li&gt;OpenTSDB
&lt;ol&gt;
&lt;li&gt;Intro &amp;amp; Architecture&lt;&#x2F;li&gt;
&lt;li&gt;OpenTSDB Internal&lt;&#x2F;li&gt;
&lt;li&gt;Asynchronous programming using deferred object ( async Hbase )&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;memcached &amp;amp; internal&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;supported-stuffs-and-tools&quot;&gt;Supported Stuffs and tools&lt;a class=&quot;zola-anchor&quot; href=&quot;#supported-stuffs-and-tools&quot; aria-label=&quot;Anchor link for: supported-stuffs-and-tools&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;Dotfiles : vim , zsh, tmux&lt;&#x2F;li&gt;
&lt;li&gt;docker &amp;amp; docker compose&lt;&#x2F;li&gt;
&lt;li&gt;Tdd. &amp;amp; unit test with python &amp;amp; java&lt;&#x2F;li&gt;
&lt;li&gt;Project pywatch4test&lt;&#x2F;li&gt;
&lt;li&gt;Ci by Jenkins &amp;amp; Travis ci using mildronize.com as a case study&lt;&#x2F;li&gt;
&lt;li&gt;Vim cheat sheet thai&lt;&#x2F;li&gt;
&lt;li&gt;PSU Latex template&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>อยากแชร์ เรื่องหลังจาการตัดสินใจ ทำไมถึงใช้เวลาทำวิจัยป.โท แค่ 7 เดือน</title>
		<published>2019-01-29T00:00:00+00:00</published>
		<updated>2019-01-29T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/7-months-finish-master-thesis/" type="text/html"/>
		<id>https://thadaw.com/posts/7-months-finish-master-thesis/</id>
		<content type="html">&lt;p&gt;อยากแชร์ เรื่องหลังจาการตัดสินใจ ทำไมถึงใช้เวลาทำวิจัยป.โท แค่ 7 เดือน (ทั้งๆ
ที่จริงๆ แล้วอาจจะต้องใช้เวลาเป็นปี)&lt;&#x2F;p&gt;
&lt;p&gt;ก่อนอื่นนะครับ ผมไม่เก่งอะไร เพียงแต่มีวิธีคิด วินัยและพันธสัญญาต่อตัวเอง และอยากมาแชร์มุมมองว่า การที่เราจะประสบความสำเร็จในเรื่องใดๆ สักเรื่องนั้น มันจะประกอบไปด้วยอะไรบ้าง
นั่นคือ ความเชื่อ, เป้าหมาย, และการรักษาการตัดสินใจตลอดเวลา (วินัย)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;khwaamechuue&quot;&gt;ความเชื่อ&lt;a class=&quot;zola-anchor&quot; href=&quot;#khwaamechuue&quot; aria-label=&quot;Anchor link for: khwaamechuue&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ก่อนอื่นขอเล่าก่อน มันอาจจะดูเว่อนะครับ 7 เดือนเสร็จได้ แต่จริงๆ มันคือแบบนั้นจริงๆ คือ หลังจบปลดประจำการทหาร ทางมหาวิทยาลัยติดต่อมาว่า &quot;ถ้าต้องการสมัครเป็นอาจารย์มหาวิทยาลัย ต้องจบวุฒิป.โทให้ทัน มีเวลาให้ 7 เดือน&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ซึ่งมีเงื่อนพ่วงท้ายว่าจะต้องมี 2 งานวิจัยด้วย, และมีคะแนนสอบภาษาอังกฤษด้วย
&quot;ผมก็ตอบว่าได้ครับ จบทันครับ&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ทั้งๆ ที่วันนั้นความคืบหน้าของวิทยานิพนธ์แค่ 25% คือ&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ปัญหาที่จะแก้ชัด&lt;&#x2F;li&gt;
&lt;li&gt;ยังไม่รู้ว่าต้องแก้ด้วยวิธีไหน (เคยหาวิธีแก้ปัญหามาแล้วร่วม 4-5 เดือน แต่ไม่เจอ)&lt;&#x2F;li&gt;
&lt;li&gt;ยังไม่รู้ว่าทำแล้วจะแก้ปัญหาได้มั้ย&lt;&#x2F;li&gt;
&lt;li&gt;ยังไม่ได้ทำการทดลอง, ไม่มีผลการทดลองใดๆ&lt;&#x2F;li&gt;
&lt;li&gt;ยังไม่ได้เขียนโปรแกรม&lt;&#x2F;li&gt;
&lt;li&gt;รายงานก็ยังไม่ได้เขียน, งานวิจัยยังไม่มีสักอัน
สรุปคือ ไม่พร้อมสักอย่างครับ
แต่วันนั้นผม ตอบไปอย่างเร็วมากครับ ด้วยความเชื่อว่า
&quot;เราทำได้&quot;
จริงๆ ผมไม่ได้คิดมากเลย แต่ผมคิดง่ายๆ ครับ ถ้าทำไม่ได้แล้วจะเสียอะไรมั้ย?&lt;&#x2F;li&gt;
&lt;li&gt;เสียเวลา&lt;&#x2F;li&gt;
&lt;li&gt;จ่ายค่าเทอมมากขึ้น&lt;&#x2F;li&gt;
&lt;li&gt;อาจจะไม่ได้งานที่อยากทำ
ความเชื่อก็เปรียบเหมือนพลังงานในตัวเรา ความหวัง ความมั่นใจในการลงมือทำอะไรสักอย่าง พอเรามั่นใจเราก็จะลงมือทำครับ
หากวันใดปราศจากความเชื่อแล้วไซร้ ก็คงไม่ต่างกับรถที่ไร้น้ำมัน&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;epaahmaay&quot;&gt;เป้าหมาย&lt;a class=&quot;zola-anchor&quot; href=&quot;#epaahmaay&quot; aria-label=&quot;Anchor link for: epaahmaay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เป้าหมายที่ดีควรจะมีภาพที่ชัดเจนและมีระยะเวลากำหนด
ซึ่งผมเองก็มีภาพที่ชัด แต่มีเวลาเป็นตัวกำหนดครับ (ก็มีเวลาแค่ 7 เดือน ทั้งๆ ที่ปกติอาจจะต้องใช้เวลาเป็นปี) แล้วเราจะคิดครับว่าทำยังไงให้ทันเวลา&lt;&#x2F;p&gt;
&lt;p&gt;นึกง่ายๆ ว่า เราอาจารย์สั่งการบ้าน ตอนสั่งใหม่ๆ ไม่ทำ คิดไม่ออก แต่พอใกล้เวลาส่ง พลังงานมาจากไหนไม่รู้ ต้องเสร็จให้ทัน ฮ่าๆๆ&lt;&#x2F;p&gt;
&lt;p&gt;เพราะว่าถ้าภาพไม่ชัดเราก็ไม่รู้ว่าเราจะอยากได้มันทำไม&lt;&#x2F;p&gt;
&lt;p&gt;เพราะว่าถ้าเดดไลน์ ไม่ชัด เราก็จะทำเรื่อยๆ เสร็จเมื่อไหร่เมื่อนั้น&lt;&#x2F;p&gt;
&lt;h2 id=&quot;kaarraksaakaartadsinaicchtl-dewlaa-winay-cchnkwaacchathuengepaahmaay&quot;&gt;การรักษาการตัดสินใจตลอดเวลา (วินัย) จนกว่าจะถึงเป้าหมาย&lt;a class=&quot;zola-anchor&quot; href=&quot;#kaarraksaakaartadsinaicchtl-dewlaa-winay-cchnkwaacchathuengepaahmaay&quot; aria-label=&quot;Anchor link for: kaarraksaakaartadsinaicchtl-dewlaa-winay-cchnkwaacchathuengepaahmaay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เมื่อมีความเชื่อมีมากพอ เราจะไม่ลืมเป้าหมาย ชนิดที่กัดไม่ปล่อย ยังไงก็ขอไม่แพ้ในเวทีนี้ละนะ&lt;&#x2F;p&gt;
&lt;p&gt;หัวข้อนี้สำคัญไม่แพ้กัน เพราะว่าเราจะต้องรักษาการตัดสินใจให้ได้ตลอดเวลา ไม่ว่าอะไรจะเกิดขึ้นเรายังคงทำมันต่อหรือไม่ ซึ่งมันจะมันจะเกิดเป็นนิสัย&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งมันจะต้องมีการวางแผนและลงมือทำ พอรู้ว่าเวลามีน้อยมากๆ เลยต้องคิดให้เยอะครับ ว่าจะทำอะไรตรงไหนบ้าง ทำให้ทำงานรอบคอบมาก แทบไม่สูญเสียโฟกัสเลย ครับ&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;คิดมากกว่าทำ จะใช้เวลาทำน้อยกว่าที่คิด
Failing to plan is planing to fail&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&quot;คนที่สำเร็จ ไม่ได้สำเร็จแล้ว ได้นิสัยแบบคนประสบความสำเร็จ
แต่ทำแต่เรื่องให้ตรงกับเงื่อนไขความสำเร็จจนเป็นนิสัย ถึงจะสำเร็จ&quot;&lt;&#x2F;p&gt;
&lt;p&gt;ชีวิตจะเป็นอย่างไรเริ่มที่ตัวเรา สร้างนิสัยแบบคนสำเร็จหรือยัง
เข้าใจเงื่อนไขความสำเร็จ แล้วจะสำเร็จจนเป็นนิสัย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sudthaaythaamwaa-thamngaanerwkhnaadniingaanlwkmay&quot;&gt;สุดท้ายถามว่า ทำงานเร็วขนาดนี้งานลวกมั้ย?&lt;a class=&quot;zola-anchor&quot; href=&quot;#sudthaaythaamwaa-thamngaanerwkhnaadniingaanlwkmay&quot; aria-label=&quot;Anchor link for: sudthaaythaamwaa-thamngaanerwkhnaadniingaanlwkmay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ด้านล่างเป็นความคิดเห็นของอาจารย์กรรมการสอบวิทยานิพนธ์ (ที่เชิญมาจากข้างนอก) ผศ.ดร.เทพฤทธิ์ ซึ่งถนัดเรื่อง cache ครับ&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;สุดท้ายนี้ ผมขออนุญาตชื่นชมท่านอาจารย์ที่ปรึกษาและ นศ อีกครั้งว่าเป็นผลงานวิทยานิพนธ์ที่มีคุณภาพประทับใจอีกหนึ่งฉบับเท่าที่ผมเคยสัมผัสมาครับ&quot;&lt;&#x2F;p&gt;
&lt;p&gt;&quot;...เพื่อเป็นวิทยาทานให้นักวิจัยรุ่นน้องๆ และผมจะขอเก็บงานดีๆ นี้ไว้อ้างอิงด้วยเช่นกันครับ&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;จงมีพันธสัญญาต่อตัวเอง ต่อความเชื่อ ต่อเป้าหมาย
แล้วพบกันที่ความสำเร็จครับ
ป.ล. งานเกือบทั้งหมดเสร็จในระยะ 7 เดือน แต่มีประเด็นเรื่องเวลาการนำเสนองานวิจัย ที่ทำให้เร็วไม่ได้จึงต้องรอเวลาเพื่อจบครับ&lt;&#x2F;p&gt;
&lt;p&gt;บทความเนื้อเขียนเพื่อทบทวนความทรงจำของตัวผมเอง&lt;&#x2F;p&gt;
&lt;p&gt;Cross Publish at Facebook &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.facebook.com&#x2F;photo&#x2F;?fbid=10218769998469109&amp;amp;set=a.1519952206806&quot;&gt;https:&#x2F;&#x2F;www.facebook.com&#x2F;photo&#x2F;?fbid=10218769998469109&amp;amp;set=a.1519952206806&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ได้ 99 คะแนนจาก Google Insights &amp; เรียนรู้การทำ web optimization</title>
		<published>2018-09-17T00:00:00+00:00</published>
		<updated>2018-09-17T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/99-score-google-insight-web-optimization/" type="text/html"/>
		<id>https://thadaw.com/posts/99-score-google-insight-web-optimization/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;Blog นี้เขียนตอนสมัยยังใช้ Jekyll อยู่ ซึ่งสามารถไปดูได้ที่ https:&#x2F;&#x2F;jekyll.mildronize.com&#x2F;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ได้ 99 คะแนนจาก Google Insights &amp;amp; เรียนรู้การทำ web optimization ผ่านการพัฒนาเว็บบล็อกให้ทันสมัย
จากการพัฒนา &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;mildronize.com&#x2F;notes&#x2F;my-blog-dev&#x2F;&quot;&gt;blog version แรก&lt;&#x2F;a&gt;  ซึ่ง clone theme Hyde ของ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;jekyllrb.com&#x2F;&quot;&gt;Jekyll&lt;&#x2F;a&gt; มาแล้วปรับแก้มาเรื่อยๆ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;sqk4d1no2xi4os0&#x2F;2018-09-17-99-score-google-insight-web-optimization-1.jpg?raw=1&quot; alt=&quot;old web design&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;gt0p9ta4da7t6gs&#x2F;2018-09-17-99-score-google-insight-web-optimization-2.jpg?raw=1&quot; alt=&quot;new web deisgn&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ตอนแรกไปลองใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;gatsbyjs.org&#x2F;&quot;&gt;GatsbyJS&lt;&#x2F;a&gt; อยู่สักพัก ซึ่งใช้ React ทั้งระบบเลย แต่สุดท้ายก็ย้ายจาก Gatsby กลับมาใช้ Jekyll เหมือนเดิม เท่าที่ลองใช้งานดู Gatsby เร็วกว่าในหลายๆ ด้านเลย ทั้งด้าน dev และ รันขึ้น production เป็น pwa ด้วย&lt;&#x2F;p&gt;
&lt;p&gt;แต่ดูเหมือนต้องปรับจูนเยอะกว่าจะได้ blog แบบที่เราต้องการ เลยไม่เอาดีกว่า ยอมใช้ Jekyll ที่ compile ช้ากว่า แต่ เราถนัดกว่า ( เทคโนโลยี แบบดั้งเดิมดี ไม่ต้องเปลี่ยนเยอะ)&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ตรงนี้จากประสบการณ์ตัวเอง เนื่องจากว่าเว็บบล็อกไม่ได้เขียนโค้ด หรือพัฒนาอยู่บ่อยๆ ส่วนใหญ่เน้นไปที่เขียนบทความใหม่ๆ มากกว่า ดังนั้น เมื่อเวลาผ่านไปนานๆ และเทคโนโลยีฝั่งเว็บไปเร็วมาก จนบางครั้งอาจจะทำให้เทคโนโลยีเว็บเดิมที่เคยใช้อยู่ทำงานไม่ได้ ใน browser สมัยใหม่ หรือการปรับเปลี่ยนให้ทันยุคทันสมัยต้องมานั่งแก้เว็บใหม่อีก&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ดังนั้น&lt;&#x2F;strong&gt; ผมเลยตัดสินใจใช้เทคโนโลยีเก่าหน่อย ที่ยังคงเป็น long term support แต่ก็ยังคงสามารถทำให้ดูทันสมัยได้ และไม่ได้ทำงานช้าด้วยซึ่งก็เหมาะสมกับเว็บบล็อกดี&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;สุดท้ายก็ตัดสินใจจูน frontend ของบล็อกเดิม ที่เป็น Jekyll ใหม่ให้เป็น Responsive มากขึ้น ทั้งแง่ของ typography ด้วย&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;phlkaarthds-bcchaak-google-insights&quot;&gt;ผลการทดสอบจาก google insights&lt;a class=&quot;zola-anchor&quot; href=&quot;#phlkaarthds-bcchaak-google-insights&quot; aria-label=&quot;Anchor link for: phlkaarthds-bcchaak-google-insights&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จากการทดสอบ google insights ก็ได้ 99 คะแนนบน mobile และ 97 คะแนนบน desktop&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;2irrnt11wei4aq7&#x2F;2018-09-17-99-score-google-insight-web-optimization-3.jpg?raw=1&quot; alt=&quot;99 score on Mobile&quot; &#x2F;&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;k6ib5pfgunc6dr0&#x2F;2018-09-17-99-score-google-insight-web-optimization-4.jpg?raw=1&quot; alt=&quot;97 score on Desktop&quot; &#x2F;&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;prabprungewbethkhonolyiiekaaaihthansmay&quot;&gt;ปรับปรุงเว็บเทคโนโลยีเก่าให้ทันสมัย&lt;a class=&quot;zola-anchor&quot; href=&quot;#prabprungewbethkhonolyiiekaaaihthansmay&quot; aria-label=&quot;Anchor link for: prabprungewbethkhonolyiiekaaaihthansmay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลักๆ ที่ปรับจูน Web สมัยเก่าให้ดูดี ทันสมัย และเร็วด้วย&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;เปลี่ยน core เป็น Bulma framework ทั้งหมด ทำให้ชีวิตการทำ responsive ง่ายขึ้น&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เปลี่ยนจากการโหลด CSS แบบ Synchronous (Blocking) ให้โหลดแบบ Async ใช้ไลบรารี่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;filamentgroup&#x2F;loadCSS&quot;&gt;LoadCSS&lt;&#x2F;a&gt; (ซึ่งแนะนำโดย Google Insights) ในการโหลด CSS เข้ามา เมื่อโหลดเสร็จ&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;phlthiiaidkhuue&quot;&gt;ผลที่ได้คือ&lt;a class=&quot;zola-anchor&quot; href=&quot;#phlthiiaidkhuue&quot; aria-label=&quot;Anchor link for: phlthiiaidkhuue&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;หน้าเว็บโหลดเร็วขึ้น แต่ข้อเสียคือ มันจะเห็นหน้าตาเว็บแบบไม่มี css ใดๆ เลย ซึ่งไม่สวยเลย 55 พอ CSS โหลดเข้ามาหน้าตาเว็บก็เป็นแบบที่เห็น แบบนี้เลยคับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;vks0ebprrdansm7&#x2F;2018-09-17-99-score-google-insight-web-optimization-5.gif?raw=1&quot; alt=&quot;load-css-async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;การใช้ &lt;strong&gt;sass&lt;&#x2F;strong&gt; ช่วยทำให้ชีวิตง่ายขึ้นเยอะในการจัดการค่าต่างๆ ในการตกแต่งหน้าเว็บ ให้มันเป็นอันหนึ่งอันเดียวกัน (consistency)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;aich-jekyll-sass-plugin-ainkaar-bundle-sass-aela-css&quot;&gt;ใช้ Jekyll sass plugin ในการ bundle sass และ css&lt;a class=&quot;zola-anchor&quot; href=&quot;#aich-jekyll-sass-plugin-ainkaar-bundle-sass-aela-css&quot; aria-label=&quot;Anchor link for: aich-jekyll-sass-plugin-ainkaar-bundle-sass-aela-css&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;(อนาคตจะไปใช้ webpack ด้วย) แยกเป็น 2 ไฟล์คือ&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;preload_styles.css&lt;&#x2F;code&gt; ไฟล์นี้ ถ้าโหลดผ่าน &lt;code&gt;LoadCSS&lt;&#x2F;code&gt; จะเหมือนรูปข้างบน จะใส่แบบปกติ ก็เดี๋ยวโดน Google หักคะแนน หาว่าโหลด stylesheet แบบ Blocking เดี๋ยวทำให้เว็บช้า &lt;strong&gt;สรุปคือ&lt;&#x2F;strong&gt; จัดการฝั่งโค้ด CSS เข้าไปใน HTML ซะเลย&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;postload_styles.css&lt;&#x2F;code&gt; ไฟล์นี้โหลดผ่าน &lt;code&gt;LoadCSS &lt;&#x2F;code&gt;ไฟล์นี้จะเป็น พวก asset ขนาดใหญ่ พวกโหลด font, กับ Icon ต่างๆ (&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;fontawesome.com&#x2F;&quot;&gt;Font Awesome&lt;&#x2F;a&gt;) ซึ่งไม่จำเป็นต้องมาก่อนครั้งแรกที่เว็บโหลดก็ได้&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;epliiynethkhonolyiihnaa-search&quot;&gt;เปลี่ยนเทคโนโลยีหน้า Search&lt;a class=&quot;zola-anchor&quot; href=&quot;#epliiynethkhonolyiihnaa-search&quot; aria-label=&quot;Anchor link for: epliiynethkhonolyiihnaa-search&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;จาก AngularJS ซึ่ง&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;831f4fb466d0f9cd513a45c299b946ca2f398aed&quot;&gt;เขียนตั้งแต่ปี 2558&lt;&#x2F;a&gt; ให้เป็น React โดยเป็นการใช้ React แบบ library จริงๆ คือเฉพาะส่วนของ content เท่านั้นที่เป็น React ที่เหลือยังคงเป็น HTML ธรรมดา (Header, Footer) ซึ่ง bundle ใส่ในไฟล์ &lt;code&gt;search.js&lt;&#x2F;code&gt; ปรับหน้า search ให้เป็น responsive บน mobile แยกต่างหากด้วย&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;3d4vqbnd424wbsh&#x2F;2018-09-17-99-score-google-insight-web-optimization-6.jpg?raw=1&quot; alt=&quot;search&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thamewb-bundle-dwy-webpack4&quot;&gt;ทำเว็บ Bundle ด้วย Webpack4&lt;a class=&quot;zola-anchor&quot; href=&quot;#thamewb-bundle-dwy-webpack4&quot; aria-label=&quot;Anchor link for: thamewb-bundle-dwy-webpack4&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เนื่องจากเป็น Static page ธรรมดา ไม่มีการทำ SPA แต่อย่างใด ดังนั้นเลยใช้การแพ็กเป็น bundle ( คือรวมทุกๆ ไฟล์ เข้ามาเป็นไฟล์เดียว หรือแบ่งเป็นหลายๆ ส่วนแล้วแต่โมดูลก่อนก็ได้ ) ซึ่ง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;webpack.js.org&#x2F;&quot;&gt;webpack&lt;&#x2F;a&gt; ก็มาตอบโจทย์ตรงนี้ได้ เพื่อให้ลดจำนวน request ส่งไปยัง server ตอนนี้เว็บแบ่งออกเป็น 3 ไฟล์ (entry)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;index.js&lt;&#x2F;code&gt; โหลดเฉพาะหน้าแรกเท่านั้น เป็นการเรียกใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;momentjs.com&#x2F;&quot;&gt;Moment.js&lt;&#x2F;a&gt; ( &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jmblog&#x2F;how-to-optimize-momentjs-with-webpack&quot;&gt;Optimize file size ของ Moment ด้วยไม่งั้นไฟล์อ้วนมาก&lt;&#x2F;a&gt;) ในการแปลงเวลาของแต่บล็อก ให้แสดงผลว่า บล็อกเขียนมาแล้วกี่วัน&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;toc.js&lt;&#x2F;code&gt; โหลดเฉพาะหน้าที่มี Table of Content จ้า มี JQuery กับ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ghiculescu&#x2F;jekyll-table-of-contents&quot;&gt;Jekyll ToC&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;search.js&lt;&#x2F;code&gt;โหลดเฉพาะหน้า Search เท่านั้น ซึ่งใช้ React ในหัวข้อก่อนหน้านี้&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;lazy-load-image&quot;&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;verlok&#x2F;lazyload&quot;&gt;Lazy load image&lt;&#x2F;a&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#lazy-load-image&quot; aria-label=&quot;Anchor link for: lazy-load-image&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;คือไม่ได้โหลด รูปทุกรูปในครั้งแรกที่เว็บโหลดแต่ จะค่อยๆ โหลดเมื่อ user scroll ผ่านเท่านั้น เพื่อลดปริมาณข้อมูลที่โหลดทั้งหมด&lt;&#x2F;p&gt;
&lt;p&gt;สุดท้ายทำ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ohldruupphaaphaebb-ebl-k-naelwemuue-ruupohldesrcchthuengcchaaesdngruupcchringaebb-medium-com&quot;&gt;โหลดรูปภาพแบบ เบลอก่อนแล้วเมื่อรูปโหลดเสร็จถึงจะแสดงรูปจริงแบบ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;medium.com&#x2F;&quot;&gt;medium.com&lt;&#x2F;a&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ohldruupphaaphaebb-ebl-k-naelwemuue-ruupohldesrcchthuengcchaaesdngruupcchringaebb-medium-com&quot; aria-label=&quot;Anchor link for: ohldruupphaaphaebb-ebl-k-naelwemuue-ruupohldesrcchthuengcchaaesdngruupcchringaebb-medium-com&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;(ตรงนี้จะแชร์ในอีกบล็อกครับ) ซึ่งตรงนี้ใช้บริการแคชรูปของ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;cloudimage.io&#x2F;&quot;&gt;Cloudimage.io&lt;&#x2F;a&gt; ซึ่งทำ cache, thumbnail ได้ง่ายมากๆ แถมให้ใช้ฟรี ตั้ง 15 GB ตรงนี้เขียน Plugin ของ Jekyll เข้ามาช่วยในการแปลง img tag ให้เป็นแบบ เบลอก่อนโหลดเสร็จด้วย&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;4t30cmbtezs3qbw&#x2F;2018-09-17-99-score-google-insight-web-optimization-7.gif?raw=1&quot; alt=&quot;image-load-blur&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;srup-singaideriiynruucchaak-google-insights&quot;&gt;สรุป สิ่งได้เรียนรู้จาก Google Insights&lt;a class=&quot;zola-anchor&quot; href=&quot;#srup-singaideriiynruucchaak-google-insights&quot; aria-label=&quot;Anchor link for: srup-singaideriiynruucchaak-google-insights&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;ให้คำแนะนำละเอียดมาก แนะนำว่าเว็บเรามีปัญหาตรงไหนแล้ว ควรจะแก้ยังไง&lt;&#x2F;li&gt;
&lt;li&gt;เหมาะสำหรับทดสอบเว็บแบบ responsive มีคะแนนแยกในส่วนของ mobile และ desktop&lt;&#x2F;li&gt;
&lt;li&gt;server response time ควรจะเร็ว ถ้าช้าจะหักคะแนนตรงนี้ไปเยอะ&lt;&#x2F;li&gt;
&lt;li&gt;Blocking rendering หรือ Synchronous rendering ตรงถ้า เอาส่วนตรงนี้ออกไปได้เว็บจะโหลดเร็วขึ้น และได้คะแนนเพิ่มด้วย&lt;&#x2F;li&gt;
&lt;li&gt;Minify HTML, JS , CSS ตรงนี้ถ้า ถ้าบีบไฟล์ source ได้เว็บจะโหลดเร็วขึ้นด้วย และไม่ถูกหักคะแนน&lt;&#x2F;li&gt;
&lt;li&gt;image compression ไม่จำเป็นเท่าไหร่นัก ถ้าดูจาก weight คะแนนของ insights แล้ว ถือว่าน้อยมาก แต่ถ้าทำด้วยจะดีมาก&lt;&#x2F;li&gt;
&lt;li&gt;redirect page ไปมา ทำให้คะแนนตกจ้า เว็บก็โหลดช้า&lt;&#x2F;li&gt;
&lt;li&gt;*** แถมการลดจำนวน request ไปยัง resource ต่างๆ ช่วยให้เว็บโหลดเร็วขึ้นด้วย ตรงนี้เราสามารถใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;webpack.js.org&#x2F;&quot;&gt;webpack&lt;&#x2F;a&gt; ช่วย bundle ได้ เพื่อรวมหลายๆ ไฟล์ is รวมเป็นไฟล์เดียว&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;singthiicchathamt-aip&quot;&gt;สิ่งที่จะทำต่อไป&lt;a class=&quot;zola-anchor&quot; href=&quot;#singthiicchathamt-aip&quot; aria-label=&quot;Anchor link for: singthiicchathamt-aip&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;ตอนนี้ยังใช้บน IE แล้วยังมีปัญหา เรื่องของ Image Loading&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Source code: https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&lt;&#x2F;p&gt;
&lt;p&gt;แล้วพบกันใหม่ สวัสดีครับ&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Cross published at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@mildronize&#x2F;%E0%B9%84%E0%B8%94%E0%B9%89-99-%E0%B8%84%E0%B8%B0%E0%B9%81%E0%B8%99%E0%B8%99%E0%B8%88%E0%B8%B2%E0%B8%81-google-insights-%E0%B9%80%E0%B8%A3%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%97%E0%B8%B3-web-optimization-9b835aeac9b&quot;&gt;Medium.com&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Getting Started TDD in 30 Seconds with Python</title>
		<published>2018-09-08T00:00:00+00:00</published>
		<updated>2018-09-08T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/getting-started-tdd-30-seconds-python/" type="text/html"/>
		<id>https://thadaw.com/posts/getting-started-tdd-30-seconds-python/</id>
		<content type="html">&lt;p&gt;Quick start to setup python script for Test Driven Development in 30 seconds&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Time start!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install Python virtual environment for human ( yay! ) &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pipenv.readthedocs.io&quot;&gt;&lt;code&gt;pipenv&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;sudo pip install pipenv
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;create a directory and enter to it&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mkdir my-tdd
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cd my-tdd
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Activate Python virtual environment, then the tool will automatically create it (if it’s not exist!)&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;pipenv shell
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Install &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.pytest.org&#x2F;&quot;&gt;pytest&lt;&#x2F;a&gt; as a dev dependency&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;pipenv install pytest --dev
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;create file and test file in any place of the directory&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python z-code&quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt; in lib.py
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function z-python&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;&lt;span class=&quot;z-keyword z-declaration z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;hello&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-function z-begin z-python&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-return z-python&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt; in lib_test.py or test_lib.py
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-python&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;lib&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function z-python&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;&lt;span class=&quot;z-keyword z-declaration z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;test_hello&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-function z-begin z-python&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-assert z-python&quot;&gt;assert&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;lib&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;hello&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-python&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;let’s test&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;pytest
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Getting result!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;bgwfkw2d70jp4xk&#x2F;Getting%20Started%20TDD%20in%2030%20Seconds%20with%20Python-02.png?raw=1&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The structure will be like this&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;lib.py
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;lib_test.py
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Pipfile
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Pipfile.lock
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;extra&quot;&gt;&lt;strong&gt;Extra!&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#extra&quot; aria-label=&quot;Anchor link for: extra&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;You can use automatically test your code when the code&#x27;s changed using &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;joeyespo&#x2F;pytest-watch&quot;&gt;pytest-watch&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;pipenv install pytest-watch
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s fun with TDD&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ptw
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Time stoppppppppppp!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As I said before, this blog will end within 30 seconds&lt;&#x2F;p&gt;
&lt;p&gt;Thanks guy, any question, pls comment&lt;&#x2F;p&gt;
&lt;p&gt;Good bye, see you&lt;&#x2F;p&gt;
&lt;p&gt;P.S. fastest blogging ever 🙏&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Cross published at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@mildronize&#x2F;getting-started-tdd-in-30-seconds-with-python-8113d6c94753&quot;&gt;Medium.com&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Promise, Async, Await ของ JS ES6+ ฉบับสั้นๆ ไม่พูดเยอะ เจ็บคอ แถม RxJS</title>
		<published>2018-09-02T00:00:00+00:00</published>
		<updated>2018-09-02T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/promise-async-await-rxjs-js-es6/" type="text/html"/>
		<id>https://thadaw.com/posts/promise-async-await-rxjs-js-es6/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;อ่านฉันหน่อย&lt;&#x2F;strong&gt;:  บทความนี้ใช้ javascript ES6 นะครับ ใครยังไม่ชินไปตามอ่านได้ใน Cheat sheet นี้เลย มีภาษาไทยด้วย&lt;&#x2F;p&gt;
&lt;p&gt;https:&#x2F;&#x2F;github.com&#x2F;mbeaudru&#x2F;modern-js-cheatsheet&#x2F;blob&#x2F;master&#x2F;translations&#x2F;th-TH.md&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;หมายเหตุ ต่อไป:&lt;&#x2F;strong&gt;  ผมเขียน Python, C เป็นหลักนะครับ Java เป็นรอง แต่เขียน Async บน Java ด้วย ดังนั้น อาจจะไม่ถูกใจขา JS&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;สวัสดีครับ บล็อกนี้มาสั้นๆ ไม่เกริ่นทีมา ว่าทำไมถึงใช้ และหลักการต่างๆ ข้ามไว้ก่อน เพราะเราขี้เกียจเขียน (ไว้ค่อยกลับมาเขียน 555)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;สรุปสั้นๆ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ใช้ &lt;strong&gt;Promise&lt;&#x2F;strong&gt; เพื่อแก้ปัญหา Callback Hell&lt;&#x2F;li&gt;
&lt;li&gt;ใช้ &lt;strong&gt;Async, Await&lt;&#x2F;strong&gt; เพื่อไม่ต้องใช้ &lt;code&gt;.then()&lt;&#x2F;code&gt; แล้วยังไงล่ะ ไปดู&lt;&#x2F;li&gt;
&lt;li&gt;เนื่องจาก Promise &lt;code&gt;resolve&lt;&#x2F;code&gt; ได้แค่ครั้งเดียว ถ้าอยาก &lt;code&gt;resolve&lt;&#x2F;code&gt; หลายครั้ง เช่นข้อมูลแบบ stream ใช้ &lt;strong&gt;RxJS&lt;&#x2F;strong&gt; เพื่อแก้ปัญหา&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;สรุปจบ ไปดูโค๊ด&lt;&#x2F;p&gt;
&lt;p&gt;เราจะเขียน Promise กันง่ายๆ คือ ให้ฟังชั่นที่ทำงานนานๆ ตัวนึงชื่อ &lt;code&gt;upperAfter&lt;&#x2F;code&gt; โดยทำหน้าที่แปลงเป็นตัวพิมพ์ใหญ่ หลังจาก 2 วินาที ไปดูตัวอย่างกัน&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;7se4umjvmx1jbgx&#x2F;promise.gif?raw=1&quot; alt=&quot;promise&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1-promise&quot;&gt;1. Promise&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-promise&quot; aria-label=&quot;Anchor link for: 1-promise&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;upperAfter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;ms&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;  &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Promise&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;resolve&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;setTimeout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;resolve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;toUpperCase&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;ms&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-new z-expr z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;start upperAfter(&amp;#39;test&amp;#39;,2000)&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;upperAfter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;test&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;2000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-promise z-ts&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;data&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Finish upperAfter(&amp;#39;test&amp;#39;,2000)&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เมื่อเรารัน &lt;code&gt;main()&lt;&#x2F;code&gt; แล้ว มันจะทำงานดังนี้&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;เรียก &lt;code&gt;upperAfter(&#x27;test&#x27;,2000)&lt;&#x2F;code&gt; จะ return เป็น Promise ออกมา&lt;&#x2F;li&gt;
&lt;li&gt;object ของ promise จะสามารถต่อด้วย &lt;code&gt;.then()&lt;&#x2F;code&gt; หรือ &lt;code&gt;.catch()&lt;&#x2F;code&gt; ก็ได้
&lt;ul&gt;
&lt;li&gt;ถ้าทำสำเร็จก็ใช้ &lt;code&gt;.then()&lt;&#x2F;code&gt;  (คือค่า ที่ถูก &lt;em&gt;resolve&lt;&#x2F;em&gt; ออกมา ในที่นี้คือ &lt;code&gt;text.toUpperCase()&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;ถ้าทำไม่สำเร็จก็ใช้ &lt;code&gt;.catch() &lt;&#x2F;code&gt; (คือค่า ที่ถูก &lt;em&gt;reject&lt;&#x2F;em&gt; ออกมา )&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;เมื่อเรียก &lt;code&gt;.then()&lt;&#x2F;code&gt; ค่าของข้อความจะมาใส่มาใน &lt;code&gt;data&lt;&#x2F;code&gt; เราก็สามารถเอา &lt;code&gt;data&lt;&#x2F;code&gt; ไปต้มยำทำแกงอะไรก็ได้ เย้ จบ!&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;ข้อสังเกตุ&lt;&#x2F;strong&gt; คือเราใช้ &lt;code&gt;.then()&lt;&#x2F;code&gt; เพื่อทำให้ Blocking i&#x2F;O หรือ Synchronous นั้นเอง คล้ายกับการเรียก callback นั้นแล แต่ &lt;code&gt;.then()&lt;&#x2F;code&gt; เราสามารถต่อกันได้ ทำให้โค้ดสวยมากขึ้น และ debug ง่ายขึ้นนะ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-async-await&quot;&gt;2. Async, Await&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-async-await&quot; aria-label=&quot;Anchor link for: 2-async-await&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เอาโค้ดข้างบนมาแก้ &lt;code&gt;main&lt;&#x2F;code&gt; ใหม่&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-async z-ts&quot;&gt;async&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;start upperAfter(&amp;#39;test&amp;#39;,2000)&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;await&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;upperAfter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;test&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;2000&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Finish upperAfter(&amp;#39;test&amp;#39;,2000)&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-arrow z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เป็นไงล่ะ ทำงานได้เหมือนเดิม แต่ชีวิตง่ายขึ้นมั้ย ทีนี้เราก็ทำตัวเหมือนเขียน Blocking I&#x2F;O หรือ Synchronous  แบบ C, Python ได้แล้ว เจ๋งป่ะล่ะ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ข้อสังเกตุ&lt;&#x2F;strong&gt; ฟังก์ชัน &lt;code&gt;main()&lt;&#x2F;code&gt; ต้องเป็น &lt;code&gt;async&lt;&#x2F;code&gt; เพื่อบอกว่าฟังก์ชันนี้มี การทำ blocking I&#x2F;O หรือ Synchronous อยู่นะ  เราใส่ &lt;code&gt;await&lt;&#x2F;code&gt; หน้า promise นั้นเอง มันจะ auto &lt;code&gt;.then()&lt;&#x2F;code&gt; ให้เลย สะดวกสุดๆ&lt;&#x2F;p&gt;
&lt;p&gt;ในบรรทัดนี้ &lt;code&gt;const data = await upperAfter(&#x27;test&#x27;,2000)&lt;&#x2F;code&gt; อารมณ์เหมือนเราได้ค่า &lt;code&gt;data&lt;&#x2F;code&gt; มาเลย แล้วก็เอาไปทำอะไรต่อก็ได้ ไม่ต้องอยู่ใน &lt;code&gt;.then()&lt;&#x2F;code&gt; แล้ว&lt;&#x2F;p&gt;
&lt;h2 id=&quot;k-npidbl-k&quot;&gt;ก่อนปิดบล็อก&lt;a class=&quot;zola-anchor&quot; href=&quot;#k-npidbl-k&quot; aria-label=&quot;Anchor link for: k-npidbl-k&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;อ่าวจบแล้ว? RxJS ล่ะ เอาแค่นี้ก่อน พอรู้ข้อจำกัดของการใช้ Promise แล้ว คราวหน้า เราสามารถไปใช้ RxJS ได้&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kh-ngaethm-aelw-promise-maachwyaekpayhaa-callback-hell-yangaing&quot;&gt;ของแถม แล้ว &lt;strong&gt;Promise&lt;&#x2F;strong&gt; มาช่วยแก้ปัญหา Callback Hell  ยังไง&lt;a class=&quot;zola-anchor&quot; href=&quot;#kh-ngaethm-aelw-promise-maachwyaekpayhaa-callback-hell-yangaing&quot; aria-label=&quot;Anchor link for: kh-ngaethm-aelw-promise-maachwyaekpayhaa-callback-hell-yangaing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;อันนี้เอาตัวอย่างมาจาก โปรเจ็ค &lt;code&gt;promise-it-wont-hurt&lt;&#x2F;code&gt; ของ https:&#x2F;&#x2F;nodeschool.io&#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;อันนี้เค้าเรียกกันว่า Callback Hell ถ้ามีมากกว่าหลายชั้นก็นี้ก็ hell จริงๆ ละคับ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;Parse&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;User&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;logIn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;user&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;pass&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;user&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;find&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;      &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;results&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;save&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;value&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;          &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;            &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; the object was saved&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;          &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แล้วถ้าใช้ Promise ช่วยล่ะ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;js&quot; class=&quot;language-js z-code&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;Parse&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;User&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;logIn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;user&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;pass&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-promise z-ts&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;user&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;find&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-promise z-ts&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;results&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;save&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-meta z-object-literal z-key z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-ts&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;value&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-promise z-ts&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; the object was saved&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-promise z-ts&quot;&gt;catch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; an error happened somewhere in the process&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เป็นไงบ้าง ดูง่ายขึ้นเยอะมั้ย ครับ&lt;&#x2F;p&gt;
&lt;p&gt;พอล่ะไม่อธิบายเยอะ เจ็บขอ แล้วพบกันใหม่ครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;aanephimetim&quot;&gt;อ่านเพิ่มเติม&lt;a class=&quot;zola-anchor&quot; href=&quot;#aanephimetim&quot; aria-label=&quot;Anchor link for: aanephimetim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mbeaudru&#x2F;modern-js-cheatsheet&quot;&gt;Modern JS Cheat sheet&lt;&#x2F;a&gt;  one-stop cheat sheet for JS developer&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;nodeschool.io&#x2F; เว็บนี้ก็ดีงาม สอน JS แบบ interactive เลย&lt;&#x2F;li&gt;
&lt;li&gt;ES6 Cheat sheet: https:&#x2F;&#x2F;github.com&#x2F;DrkSephy&#x2F;es6-cheatsheet อันนี้ก็ดีนะ ไปดูได้&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Cross published at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@mildronize&#x2F;promise-async-await-%E0%B8%82%E0%B8%AD%E0%B8%87-js-es6-%E0%B8%89%E0%B8%9A%E0%B8%B1%E0%B8%9A%E0%B8%9C%E0%B8%AD%E0%B8%A1%E0%B9%80%E0%B8%9E%E0%B8%A3%E0%B8%B5%E0%B8%A2%E0%B8%A7-%E0%B9%84%E0%B8%A1%E0%B9%88%E0%B8%9E%E0%B8%B9%E0%B8%94%E0%B9%80%E0%B8%A2%E0%B8%AD%E0%B8%B0-%E0%B9%80%E0%B8%88%E0%B9%87%E0%B8%9A%E0%B8%84%E0%B8%AD-%E0%B9%81%E0%B8%96%E0%B8%A1-rxjs-12b9e7b32392&quot;&gt;Medium.com&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธีตั้งค่าการใช้งาน Github (แบบไม่ต้องกรอกรหัสผ่านทุกครั้ง) ผ่าน SSH บน Windows</title>
		<published>2018-08-28T00:00:00+00:00</published>
		<updated>2018-08-28T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/setup-github-via-ssh-using-putty-on-windows-th/" type="text/html"/>
		<id>https://thadaw.com/posts/setup-github-via-ssh-using-putty-on-windows-th/</id>
		<content type="html">&lt;p&gt;ขั้นตอนการตั้งค่าการใช้งาน Github  แบบไม่ต้องกรอกรหัสผ่านทุกครั้ง บน windows&lt;&#x2F;p&gt;
&lt;p&gt;จริงๆ แล้ว ก็ใช้ git มานานแต่บางครั้งก็ขีเกียจตั้งค่า โดยเฉพาะบน Windows มันมีหลายวิธีมาก แต่ผมถนัดวิธีนี้ทุกสุดและยุ่งยากน้อยสุดแล้ว (เขียนไม่ค่อยละเอียดเท่าไหร่ เหมาะสำหรับคนที่คุ้นชินกับ Putty อยู่แล้ว)&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.chiark.greenend.org.uk&#x2F;~sgtatham&#x2F;putty&#x2F;latest.html&quot;&gt;ดาวโหลด&lt;&#x2F;a&gt; และติดตั้ง Putty ไว้ในเครื่องก่อนเลย แนะนำให้ลงแบบ &lt;code&gt;MSI (‘Windows Installer’)&lt;&#x2F;code&gt;เพราะมันจะมีโปรแกรมเพื่อนบ้านมาให้ด้วย ในโพสนี้จะใช้ &lt;code&gt;puTTYgen&lt;&#x2F;code&gt; และ &lt;code&gt;plink&lt;&#x2F;code&gt; หรือใครจะลงแยกก็ได้&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ตั้งค่า system environment variable ให้เรียบร้อย ถ้าลงผ่าน installer น่าจะตั้งค่าไว้แล้ว&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;สร้าง Private Key และ Public Key จาก &lt;code&gt;puTTYgen&lt;&#x2F;code&gt; โดยเลือกเป็น RSA 2048 (ใครจะเลือกตัวอื่นก็ได้นะ เผื่อตัวที่ดีกว่านี้ในอนาคต) กด generate แล้วก็เอา mouse เป็นวนๆ ที่ว่างๆ จนแถบโหลดเต็ม แล้วก็ตั้งค่ารหัสผ่าน (key passphrase) จะใส่ตรงที่มีการใช้ key นี้ทุกครั้ง (จะไม่ตั้งก็ได้นะ จะได้ตามชื่อบล็อกพอดี) &lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;7d1cqu99b93pv1w&#x2F;1.png?raw=1&quot; alt=&quot;1&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;จากนั้นก็อปปี้ public key จาก &lt;code&gt;puTTYgen&lt;&#x2F;code&gt; ตัวเดิมไปใส่ใน[หน้า SSH ของการตั้งค่า github ของเรา https:&#x2F;&#x2F;github.com&#x2F;settings&#x2F;keys &lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;pxikmsgglo273yf&#x2F;2.PNG?raw=1&quot; alt=&quot;2&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ตั้งค่า environment variable &lt;code&gt;GIT_SSH&lt;&#x2F;code&gt; ให้เป็น path ไปยัง &lt;code&gt;plink&lt;&#x2F;code&gt; เช่น&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;SET GIT_SSH=C:\path\to\PuTTY\plink.exe
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เพิ่ม SSH key ลงไปในโปรแกรม &lt;code&gt;Pageant&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;C:\path\to\PuTTY\pageant.exe c:\pathtoprivate-ssh-key.ppk`
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ตรวจสอบการเชื่อมต่อ เป็นอันเสร็จ&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;plink -v git@github.com
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ถ้าได้ผลลัพธ์ประมาณนี้ถือว่าผ่านแล้วครับ&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Hi mildronize! You&amp;#39;ve successfully authenticated, but GitHub does not provide shell access.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Server sent command exit status 1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Disconnected: All channels closed
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;kh-bkhunaehlngthiimaadii-khrab&quot;&gt;ขอบคุณแหล่งที่มาดีๆ ครับ&lt;a class=&quot;zola-anchor&quot; href=&quot;#kh-bkhunaehlngthiimaadii-khrab&quot; aria-label=&quot;Anchor link for: kh-bkhunaehlngthiimaadii-khrab&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.richardkotze.com&#x2F;top-tips&#x2F;git-on-windows-in-command-line&quot;&gt;Git and Putty on Windows in command line&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;vladmihalcea.com&#x2F;tutorials&#x2F;git&#x2F;windows-git-ssh-authentication-to-github&#x2F;&quot;&gt;Windows git SSH authentication to GitHub&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;kh-ngaethm&quot;&gt;ของแถม&lt;a class=&quot;zola-anchor&quot; href=&quot;#kh-ngaethm&quot; aria-label=&quot;Anchor link for: kh-ngaethm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลายๆ คนอาจจะเข้าไปที่ git directory บนเครื่องเราแล้ว ก็ยังต้องใส่ username และ password เหมือนเดิมอยู่อีก อย่าลืมเปลี่ยน remote URL จาก HTTPS เป็น SSH นะครับ เช่น&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าดูที่ github URL เราจะเห็นหน้าตาประมาณนี้ &lt;code&gt;https:&#x2F;&#x2F;github.com&#x2F;USERNAME&#x2F;REPOSITORY&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;เช่นถ้าเรา username: &lt;code&gt;mildronize&lt;&#x2F;code&gt; และ github repo คือ &lt;code&gt;mildronize.github.io&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ดังนั้น URL จะมีหน้าตาประมาณนี้ &lt;code&gt;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;เราอาจจะ clone ด้วย HTTPS มา สังเกตุคือที่ URL จะขึ้นต้นด้วย HTTPS เช่น&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; clone https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;แต่ถ้าเรา clone ด้วย SSH สังเกตุที่ URL จะขึ้นต้นด้วย &lt;code&gt;git@github.com&lt;&#x2F;code&gt; มาหน้าตาจะประมาณนี้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; clone git@github.com:mildronize&#x2F;mildronize.github.io.git&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;เข้าเรื่องกันเลย ไปดูขั้นตอนการเปลียนจาก remote URL จาก HTTPS เป็น SSH&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kaarepliiynaipaich-remote-urls-ssh-cchaak-https&quot;&gt;การเปลี่ยนไปใช้ remote URLs SSH จาก HTTPS&lt;a class=&quot;zola-anchor&quot; href=&quot;#kaarepliiynaipaich-remote-urls-ssh-cchaak-https&quot; aria-label=&quot;Anchor link for: kaarepliiynaipaich-remote-urls-ssh-cchaak-https&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;cd&lt;&#x2F;code&gt; ไปที่ git directory ของเราก่อนนะ&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ให้ใช้ &lt;code&gt;git remote -v&lt;&#x2F;code&gt; เพือดูว่าตอนนี้ directory นี้ชี้ไปที่ไหน&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;git remote -v
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;origin  https:&#x2F;&#x2F;github.com&#x2F;USERNAME&#x2F;REPOSITORY.git (fetch)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;origin  https:&#x2F;&#x2F;github.com&#x2F;USERNAME&#x2F;REPOSITORY.git (push)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เปลียนจาก remote URL จาก HTTPS เป็น SSH  &lt;code&gt;git remote set-url&lt;&#x2F;code&gt; command.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;git remote set-url origin git@github.com:USERNAME&#x2F;REPOSITORY.git
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Verify that the remote URL has changed.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;git remote -v
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# Verify new remote URL
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;origin  git@github.com:USERNAME&#x2F;REPOSITORY.git (fetch)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;origin  git@github.com:USERNAME&#x2F;REPOSITORY.git (push)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;kh-bkhunkh-muulcchaak&quot;&gt;ขอบคุณข้อมูลจาก&lt;a class=&quot;zola-anchor&quot; href=&quot;#kh-bkhunkh-muulcchaak&quot; aria-label=&quot;Anchor link for: kh-bkhunkh-muulcchaak&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;help.github.com&#x2F;articles&#x2F;changing-a-remote-s-url&#x2F;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;เป็นไงบ้างครับ ไม่ยากเลยใช่มั้ยครับ จริงๆ เขียนให้ตัวเองอ่านด้วย ไว้พบกันใหม่ สวัสดีครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>รู้จักกับฐานข้อมูลอนุกรมเวลา OpenTSDB กันเถอะ</title>
		<published>2018-08-13T00:00:00+00:00</published>
		<updated>2018-08-13T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/introduction-to-open-time-series-database-th/" type="text/html"/>
		<id>https://thadaw.com/posts/introduction-to-open-time-series-database-th/</id>
		<content type="html">&lt;p&gt;สวัสดีครับ ผมชื่อมายนะคับ เนื่องจากผมทำวิทยานพินธ์ปริญญาโท เกี่ยวกับการปรับปรุงประสิทธิภาพของฐานข้อมูลอนุกรมเวลา OpenTSDB และบ้านเราก็ยังไม่ค่อยมีคนพูดถึงเรื่องนี้เท่าไหร่นัก ถือว่าเป็นโอกาสดีที่จะนำความรู้มาแบ่งปันกันครับ&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ถ้าใครยังไม่รู้จักกับฐานข้อมูลอนุกรมเวลา (Time Series Database) หรือยังใหม่สำหรับเรื่องนี้ หรือสามารถตามอ่านได้ในบทความก่อนหน้านี้ครับ &lt;a href=&quot;&#x2F;th&#x2F;introduction-to-time-series-database-th&#x2F;&quot;&gt;ทำไมเราถึงควรใช้ฐานข้อมูลอนุกรมเวลาสำหรับ &quot;ข้อมูลอนุกรมเวลา&quot; (Time Series Database)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;OpenTSDB ถูกใช้ในบริษัทใหญ่ๆ อย่าง eBay, Yahoo, Pinterest, Box, Bitbucket และบริษัทใหญ่ๆ อีกหลายบริษัท ซึ่งในบทความนี้ผมจะแนะนำเบื้องต้นเกี่ยวกับ OpenTSDB ข้อดี และข้อควรระวัง รวมถึงตัวอย่างการ query หลักการทำงานคร่าวๆ ว่ากันแล้ว&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tl-dr-yaawaipaim-aan&quot;&gt;TL;DR (ยาวไปไม่อ่าน):&lt;a class=&quot;zola-anchor&quot; href=&quot;#tl-dr-yaawaipaim-aan&quot; aria-label=&quot;Anchor link for: tl-dr-yaawaipaim-aan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;opentsdb.net&quot;&gt;OpenTSDB&lt;&#x2F;a&gt; คือฐานข้อมูลอนุกรมเวลา Open Source บนฐานข้อมูล &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;hbase.apache.org&quot;&gt;HBase&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;สรุปความสามารถเด่นๆ ดังนี้&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;สามารถขยายตัวได้ (Scalablity) และมีความคงทนของข้อมูลสูงอีกด้วย ( Availability) สรุปง่ายๆ คือ อาศัยความสามารถของ HBase และ Hadoop เป็นจุดเด่น&lt;&#x2F;li&gt;
&lt;li&gt;เหมาะสำหรับข้อมูลอนุกรมเวลาขนาดใหญ่&lt;&#x2F;li&gt;
&lt;li&gt;1 data point จัดเก็บได้เฉพาะ เวลา (timestamp) และตัวเลข (ค่าของข้อมูล)&lt;&#x2F;li&gt;
&lt;li&gt;การ Query มี syntax เป็นของตัวเองผ่าน HTTP API&lt;&#x2F;li&gt;
&lt;li&gt;สามารถทำ post processing ได้เช่น downsampling, rate, interoperation&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;จริงๆ แล้วทุกวันนี้เราน่าจะได้ยินเกี่ยวกับอนุกรมเวลามากขึ้น และใช้กันบ่อยขึ้น บางคนอาจจะจะรู้จักในนามของกราฟหุ้น หรือเทคโนโลยีที่เป็นที่นิยมอยู่ตอนนี้คือ Internet of Thing โดยมองคอนเซ็ปว่าทุกอย่างสามารถต่ออินเตอร์เน็ตได้&lt;&#x2F;p&gt;
&lt;p&gt;ดังนั้นในอนาคตเราก็จะมีข้อมูลเกิดขึ้นอย่างมหาศาล ลองคิดเล่นๆ ว่า หลอดไฟทุกดวงในประเทศต่ออินเตอร์เน็ต และส่งข้อมูลสถานะของมันออกมาทุกๆ วินาที เป็นระยะเวลาสัก 1 ปี แค่นี้ก็จินตนาการไม่ออกแล้วว่าข้อมูลจะมากขึ้น หรือจริงๆ แล้วอนุกรมเวลาครอบคลุมทุกอย่างที่มีความสัมพันธ์กับเวลาเลยทีเดียว&lt;&#x2F;p&gt;
&lt;p&gt;เชื่อว่าหลายๆ คนอาจจะยังไม่คุ้นชินกับฐานข้อมูลอนุกรมเวลา หรือ OpenTSDB เพราะในบ้านไม่ค่อนมีคนพูดถึงมากนัก รวมถึงในฝั่งงานวิจัยเองก็ยังคงเป็นเรื่องที่ใหม่มากๆ (เปเปอร์ที่ survey เกี่ยวกับฐานข้อมูลอนุกรมเวลาเพิ่งออกเมื่อปีที่แล้วเลย 2017)&lt;&#x2F;p&gt;
&lt;p&gt;แต่ถ้าเราต้องเก็บข้อมูลอนุกรมเวลาขนาดใหญ่ และดึงข้อมูลออกมาวิเคราะห์แล้ว OpenTSDB ตอบโจทย์ได้ดีมาก เพราะสามารถทำงานได้เร็วกว่าพวก database ทั่วๆ ไป พวก MySQL, MongoDB, HBase&lt;&#x2F;p&gt;
&lt;h2 id=&quot;opentsdb-open-time-series-database&quot;&gt;OpenTSDB (Open Time series database)&lt;a class=&quot;zola-anchor&quot; href=&quot;#opentsdb-open-time-series-database&quot; aria-label=&quot;Anchor link for: opentsdb-open-time-series-database&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;2zprjjijpfo8y1t&#x2F;2018-08-13-%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%B9%E0%B8%A5%E0%B8%AD%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B9%80%E0%B8%A7%E0%B8%A5%E0%B8%B2%20OpenTSDB%20%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-3.jpg?raw=1&quot; alt=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;2zprjjijpfo8y1t&#x2F;2018-08-13-%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%B9%E0%B8%A5%E0%B8%AD%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B9%80%E0%B8%A7%E0%B8%A5%E0%B8%B2%20OpenTSDB%20%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-3.jpg?dl=0&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;OpenTSDB ถูกสร้างครั้งแรกโดย StumbleUpon ซึ่งคนที่ดูแลหลักๆ คือ Yahoo โดยเจ้าดังๆ ที่มีใช้ก็มี eBay, Atlassian หรือบางคนอาจจะรู้จักในนาม bitbucket, Box, Pinterest , Tumblr, MapR, Cloudflare และอีกหลายๆบริษัทเลย&lt;&#x2F;p&gt;
&lt;p&gt;จุดแข็งของ OpenTSDB ที่ทำให้ผมชอบ และหลงรักคือการออกแบบอยู่บน HBase&lt;&#x2F;p&gt;
&lt;p&gt;แล้ว OpenTSDB คืออะไร หน้าเว็บหลักเค้าบอกว่าแบบนี้คับ&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Scalable Time Series Database
Store and serve massive amounts of time series data without losing granularity.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ก็คือฐานข้อมูลที่เหมาะสำหรับการเก็บข้อมูลอนุกรมเวลาขนาดใหญ่บนฐานข้อมูล HBase ซึ่งสืบทอดความสามารถของ HBase ซึ่งอยู่ใน ecosystem ของ Hadoop โดยมีความสามารถหลักๆ ประมาณนี้ครับ&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ตัว HBase เองมีความสามารถในการจัดเก็บข้อมูลแบบกระจายตัวที่มีความสามารถในการขยายตัวได้ดีมากในแบบ horizontal ( Scalability )อีกทั้งยังมีความคงทนของข้อมูลสูงอีกด้วย (Availability)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;โดยเริ่มต้นเอง พัฒนามาเพื่อใช้สำหรับในงาน Monitoring ระบบคอมพิวเตอร์ ต่างๆ ซึ่งมี ตัวที่เป็นสคริปซ์ (เรียกว่า &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;opentsdb.net&#x2F;docs&#x2F;build&#x2F;html&#x2F;user_guide&#x2F;utilities&#x2F;tcollector.html&quot;&gt;Tcollector&lt;&#x2F;a&gt;) ไว้สำหรับส่ง data เข้าสู่ OpenTSDB ด้วย เช่นการ monitor สถานะของ mysql หรือ พวก redis เป็นต้น และข้อมูลที่เก็บเป็นแบบ time series เท่านั้น&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;OpenTSDB ยังมี HTTP API สำหรับการ write และ read ข้อมูลลงฐานข้อมูล รวมถึงหน้าตา dashboard แบบง่ายๆ ให้ใช้งานด้วย (visualization tool)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ข้อดีอย่างหนึ่งของ OpenTSDB คือการเก็บ data points ทั้งหมด ซึ่งไม่เหมือนบางฐานข้อมูล เช่น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;oss.oetiker.ch&#x2F;rrdtool&#x2F;&quot;&gt;RDDtool&lt;&#x2F;a&gt; ซึ่งตัวนึงที่ใช้มากในระบบ monitoring ซึ่งมันจะลดจำนวนจุดที่มีบันทึกนานมาแล้ว โดยการเอามารวมกัน เพื่อการลดพื้นที่การจัดเก็บ&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ดังนั้น OpenTSDB จึงเหมาะสำหรับจัดเก็บข้อมูลเซนเซอร์หรือข้อมูล IoT หรือแม้แต่ time series ทั่วๆ ไปได้ ซึ่งทุกๆ จุดมีประโยชน์ต่อการนำไปวิเคราะห์ข้อมูล&lt;&#x2F;p&gt;
&lt;h3 id=&quot;taw-yaangkaar-query&quot;&gt;ตัวอย่างการ query&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangkaar-query&quot; aria-label=&quot;Anchor link for: taw-yaangkaar-query&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;เพื่อให้เห็นภาพมากขึ้น ขอยกตัวอย่างการ query ข้อมูลจากฐานข้อมูล OpenTSDB นะครับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;9f7oa9mnbfntb20&#x2F;2018-08-13-%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%B9%E0%B8%A5%E0%B8%AD%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B9%80%E0%B8%A7%E0%B8%A5%E0%B8%B2%20OpenTSDB%20%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-4.jpg?raw=1&quot; alt=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;9f7oa9mnbfntb20&#x2F;2018-08-13-%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%B9%E0%B8%A5%E0%B8%AD%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B9%80%E0%B8%A7%E0%B8%A5%E0%B8%B2%20OpenTSDB%20%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-4.jpg?dl=0&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;OpenTSDB มี Web GUI เป็นของตัวเอง และสามารถใช้ HTTP API ได้ จากรูปข้างบน เราสามารถกำหนดเวลา ตั้งต้น และสิ้นสุด และชื่อของอนุกรมเวลาได้ (ทางซ้ายมือ)&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งผลลัพธ์ก็ได้ JSON ดังรูปทางขวามือคับ ซึ่ง data point จะอยู่ในรูปแบบของ key และ value ระหว่าง timestamp และค่าของมันคับ&lt;&#x2F;p&gt;
&lt;p&gt;หลายๆ คนอาจจะสงสัยแล้วว่า OpenTSDB ทำงานยังไง แล้วทีนี้เราก็มาดู architecture ภาพรวมคร่าวๆ กันนะครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;opentsdb-thamngaan-yaangair&quot;&gt;Opentsdb ทำงานอย่างไร&lt;a class=&quot;zola-anchor&quot; href=&quot;#opentsdb-thamngaan-yaangair&quot; aria-label=&quot;Anchor link for: opentsdb-thamngaan-yaangair&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;9u78y13ja2da3s4&#x2F;2018-08-13-%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%B9%E0%B8%A5%E0%B8%AD%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B9%80%E0%B8%A7%E0%B8%A5%E0%B8%B2%20OpenTSDB%20%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-5.png?raw=1&quot; alt=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;9u78y13ja2da3s4&#x2F;2018-08-13-%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%B9%E0%B8%A5%E0%B8%AD%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B9%80%E0%B8%A7%E0%B8%A5%E0%B8%B2%20OpenTSDB%20%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-5.png?dl=0&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;รูปจาก&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;opentsdb.net&#x2F;overview.html&quot;&gt;หน้าเว็บหลักของ OpenTSDB&lt;&#x2F;a&gt;  แสดงสถาปัตยกรรมของ OpenTSDB&lt;&#x2F;p&gt;
&lt;p&gt;OpenTSDB จะสร้าง worker ที่แตก thread ออกมา ซึ่งเรียกว่า TSD (Time Series Daemon) สำหรับจัดการ job ของ OpenTSDB ซึ่งจะต้องมี worker (หรือ TSD) อย่างน้อย 1 ตัว แต่ละตัวทำงานไม่เกี่ยวข้องกัน ถ้าดูจากรูปข้างบน คือ จะไม่มีเส้น ระหว่าง TSD แต่จะต่อตรงกับ HBase ทีเดียวเลย&lt;&#x2F;p&gt;
&lt;p&gt;หลักๆ คือ TSD ทำหน้าที่เป็นตัวกลางระหว่างการเขียนและการอ่านของ OpenTSDB กับ HBase&lt;&#x2F;p&gt;
&lt;p&gt;ผมขอแนะนำ time series database ที่ชื่อ OpenTSDB ไว้แต่เพียงแค่นี้ครับ หลังจากนี้จะเป็นสรุปข้อดี ข้อเด่น และข้อควรระวังในการนำ OpenTSDB ไปใช้ จากประสบการณ์การใช้งานของผมเอง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;kh-diikh-ng-opentsdb&quot;&gt;ข้อดีของ OpenTSDB&lt;a class=&quot;zola-anchor&quot; href=&quot;#kh-diikh-ng-opentsdb&quot; aria-label=&quot;Anchor link for: kh-diikh-ng-opentsdb&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;ทำงานเร็วกว่าฐานข้อมูลเอนกประสงค์ทั่วๆ ไปมาก&lt;&#x2F;li&gt;
&lt;li&gt;รองรับการขยายตัวได้ดีเมื่อเทียบกับ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;prometheus.io&#x2F;docs&#x2F;introduction&#x2F;comparison&#x2F;#prometheus-vs.-opentsdb&quot;&gt;prometheus&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;iopscience.iop.org&#x2F;article&#x2F;10.1088&#x2F;1742-6596&#x2F;664&#x2F;4&#x2F;042036&#x2F;pdf&quot;&gt;InfluxDB, Elasticsearch&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;มีการ compaction เพื่อลดขนาดของพื้นที่ที่ใช้จัดเก็บข้อมูล&lt;&#x2F;li&gt;
&lt;li&gt;สามารถปรับจูนประสิทธิภาพได้เยอะ&lt;&#x2F;li&gt;
&lt;li&gt;เป็น Open Source และมี Commnuity ที่โอเคพอควร&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;kh-khwrrawangkh-ng-opentsdb&quot;&gt;ข้อควรระวังของ OpenTSDB&lt;a class=&quot;zola-anchor&quot; href=&quot;#kh-khwrrawangkh-ng-opentsdb&quot; aria-label=&quot;Anchor link for: kh-khwrrawangkh-ng-opentsdb&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;เนื่องจากเป็นฐานข้อมูลที่ทำงานบน HBase ดังนั้นการติดตั้งและตั้งค่าอาจจะยุ่งยาก&lt;&#x2F;li&gt;
&lt;li&gt;สามารถเก็บเวลาได้แค่ 2 หน่วยคือ วินาที และ มิลลิวินาที&lt;&#x2F;li&gt;
&lt;li&gt;ค่าที่บันทึกได้มีแค่ตัวเลข ทศนิยมหรือจำนวนเต็ม ไม่สามารถเก็บข้อความได้&lt;&#x2F;li&gt;
&lt;li&gt;เนื่องจากยังไม่มีมาตรฐานการออกแบบฐานข้อมูลอนุกรมเวลา ดังนั้น API การใช้งานจึงเฉพาะเจาะจงสำหรับ OpenTSDB เท่านั้น&lt;&#x2F;li&gt;
&lt;li&gt;บางระบบอาจจะยังไม่ตอบโจทย์เพราะว่า OpenTSDB อาจจะ general เกินไป&lt;&#x2F;li&gt;
&lt;li&gt;ยังไม่มีแคชในส่วนของการ Query ข้อมูล ซึ่งใน roadmap ของ OpenTSDB 3.0 บอกว่าจะใส่เข้ามา&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;ส่วนผมเองได้ออกแบบและพัฒนากลไกแคชสำหรับ OpenTSDB โดยใช้ Memcached ซึ่งจะปีพิมพ์ในงานประชุมวิชาการ ISCIT 2018 ด้วยครับ บล็อกหน้าจะอธิบายในส่วนถัดๆไป คับ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ในบทความต่อไปถัดไปจะพูดถึง&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Internal OpenTSDB&lt;&#x2F;li&gt;
&lt;li&gt;Asynchorous programming using deferred object ( async Hbase )&lt;&#x2F;li&gt;
&lt;li&gt;Memcached &amp;amp; internal&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ไว้พบกันใหม่โอกาสหน้าครับ สวัสดีครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hmaayehtu&quot;&gt;หมายเหตุ&lt;a class=&quot;zola-anchor&quot; href=&quot;#hmaayehtu&quot; aria-label=&quot;Anchor link for: hmaayehtu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ใช้ OpenTSDB 2.3.0 เป็นตัวอ้างอิงนะครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ทำไมเราถึงควรใช้ฐานข้อมูลอนุกรมเวลาสำหรับ ข้อมูลอนุกรมเวลา (Time Series Database)</title>
		<published>2018-08-08T00:00:00+00:00</published>
		<updated>2018-08-08T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/introduction-to-time-series-database-th/" type="text/html"/>
		<id>https://thadaw.com/posts/introduction-to-time-series-database-th/</id>
		<content type="html">&lt;p&gt;ปัจจุบันนี้ internet of thing หรือ IoT ก็ได้เข้ามามีบทบาทในอุตสาหกรรมและเทคโนโลยี ซึ่งใน สถาปัตยกรรมของ IoT เอง ก็มีหลายชั้น ตั้งแต่เซ็นเซอร์เก็บข้อมูล ชั้นเก็บข้อมูล รวมไปถึงการแสดงข้อมูลให้ผู้ใช้ ตามรูป IoT Wolrd Forum ได้ทำรูปอ้างอิงลำดับชั้นของ IoT
&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;nz351ddv6aw6v51&#x2F;2018-08-13-%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%B9%E0%B8%A5%E0%B8%AD%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B9%80%E0%B8%A7%E0%B8%A5%E0%B8%B2%20OpenTSDB%20%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-0.jpeg?raw=1&quot; alt=&quot;IoT layer by IoT Wolrd Forum&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ตรงนี้ขอไม่ลงรายละเอียดของ IoT มากนัก จากรูปข้างบน เราจะเห็นได้ว่าตั้งแต่ layer ที่ 1 ถึง layer ที่ 7 หรือก็คือตั้งแต่เซนเซอร์หรืออุปกรณ์ที่รวบรวมหรือทำงานหรือควบคุม ต่างๆ ไปจนถึงชั้นของ application และการจัดการ โดยในบทความนี้จะกล่าวถึง&lt;strong&gt;ฐานข้อมูล OpenTSDB ซึ่งจะอยู่ใน Layer ที่ 4-5&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;IoT เองก็เก็บข้อมูลในลักษณะอนุกรมเวลาเป็นส่วนใหญ่ รวมถึงสัญญาไฟฟ้า (signal) สัญญาณดิจิตอลเองก็เป็นอนุกรมเวลา แต่เมื่อข้อมูลใหญ่มากขึ้นการจัดเก็บข้อมูลอนุกรมเวลาในรูปแบบเดิมๆ อาจจะทำให้ระบบทำงานช้ากว่าที่ควรจะเป็น เช่น general purpose database อย่าง  MySQL, PostgreSQL&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;แล้วอนุกรมเวลาคืออะไร ลองไปดูกันครับ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;จริงๆ ถ้าคนเรียนสายคณิตศาสตร์คงคุ้นเคยกับคำๆ นี้ดีอยู่แล้ว แต่ผมขออธิบายง่ายๆ อย่างนี้นะคับ&lt;&#x2F;p&gt;
&lt;p&gt;สมมติว่า ถ้าเราวัดอุณหภูมิของ อ.หาดใหญ่ ทุกๆ ชั่วโมงตั้งแต่ 9 โมงเช้าถึง 6 โมงเย็น แล้วเราก็จดอุณหภูมิไว้ เราก็สามารถนำข้อมูลมาพล็อตเป็นกราฟ ในรูปข้างล่างทางขวามือได้ นี่คือ อนุกรมเวลาแบบง่ายๆ คับ คือมี เวลากับค่าที่เราบันทึก&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;036qgbbs3dy6sao&#x2F;2018-08-13-%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%B9%E0%B8%A5%E0%B8%AD%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B9%80%E0%B8%A7%E0%B8%A5%E0%B8%B2%20OpenTSDB%20%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-1.jpeg?raw=1&quot; alt=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;036qgbbs3dy6sao&#x2F;2018-08-13-%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%B9%E0%B8%A5%E0%B8%AD%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B9%80%E0%B8%A7%E0%B8%A5%E0%B8%B2%20OpenTSDB%20%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-1.jpeg?dl=0&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;Analysis-Time-Introduction-Chapman-Statistical&#x2F;dp&#x2F;1584883170&quot;&gt;อนุกรมเวลา&lt;&#x2F;a&gt; ก็คือ ชุดข้อมูลที่เรียงลำดับตามเวลา
โดยอนุกรมเวลาประกอบไปด้วยจุดข้อมูล (data point) ซึ่งในแต่ละจุดข้อมูลมีเวลาที่บันทึก และค่าที่วัดได้ ณ เวลานั้นๆ
ข้อมูลอนุกรมเวลาส่วนใหญ่แล้วใช้ในการจัดเก็บข้อมูลจากสภาพแวดล้อมต่างๆ ขึ้นอยู่กับการใช้งาน โดยในหลายๆงานก็ได้นำข้อมูลอนุกรมเวลาไปใช้ เช่น การพยากรณ์สภาพอากาศ, ระบบคอมพิวเตอร์, การจราจร, กระบวนทางเคมี หรือแม้กระทั่ง การพยากรณ์แนวโน้มของราคาหุ้น&lt;&#x2F;p&gt;
&lt;p&gt;ตัวอย่างของข้อมูลอนุกรมเวลาในกรณีของการเก็บข้อมูลสภาพอากาศ เช่น&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ลำดับของอุณหภูมิที่ถูกบันทึกเป็นรายชั่วโมง&lt;&#x2F;li&gt;
&lt;li&gt;การบันทึกความชื้นทุกชั่วโมง&lt;&#x2F;li&gt;
&lt;li&gt;การบันทึกความเร็วทุกๆ หนึ่งนาที&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ระยะห่างระหว่างเวลาที่บันทึกของข้อมูลแต่ละจุดจะเป็นเท่าใดก็ได้&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;thaankh-muul-nukrmewlaa&quot;&gt;ฐานข้อมูลอนุกรมเวลา&lt;a class=&quot;zola-anchor&quot; href=&quot;#thaankh-muul-nukrmewlaa&quot; aria-label=&quot;Anchor link for: thaankh-muul-nukrmewlaa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ช่วงนี้ฐานข้อมูลอนุกรมเวลาเริ่มดังกันขึ้นเยอะแล้ว จาก&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;prometheus.io&#x2F;blog&#x2F;2016&#x2F;05&#x2F;09&#x2F;prometheus-to-join-the-cloud-native-computing-foundation&#x2F;&quot;&gt;ข่าวที่ฐานข้อมูลอนุกรมเวลา Prometheus เข้าร่วมกับ Cloud Native Computing Foundation&lt;&#x2F;a&gt;
หลังจากที่ศึกษามาสักพักเปเปอร์ survey ด้าน time series ก็ออกมาแล้วครับ
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;ieeexplore.ieee.org&#x2F;document&#x2F;8012550&#x2F;&quot;&gt;Time Series Management Systems: A Survey&lt;&#x2F;a&gt; จึงเป็นโอกาสที่ดีจะเขียนบทความถึงฐานข้อมูลอนุกรมเวลาครับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ทำไมถึงได้มีฐานข้อมูลอนุกรมเวลาเกิดขึ้นแล้วเหมาะสำหรับระบบแบบไหน?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;คุณ Søren ใน&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;ieeexplore.ieee.org&#x2F;document&#x2F;8012550&#x2F;&quot;&gt;เปเปอร์&lt;&#x2F;a&gt; survey บอกว่า TSMS (Time Series Management System) หรือ TSDB (Time Series Database) ก็ได้ ถ้าเป็น TSMS จะครอบคลุมความหมายมากกว่า เพราะบางระบบไม่ใช่แค่ฐานข้อมูล โดยฐานข้อมูลอนุกรมเวลาเกิดขึ้นจากความต้องการที่เฉพาะเจาะจงมากขึ้น ดังนี้&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Database Management System (DBMS) กับ (Relational Database Management System (RDBMS) ทั่วๆ ไปยังไม่ตอบโจทย์เท่าไหร่นัก&lt;&#x2F;strong&gt;เมื่อ เรามีเครือข่ายของเซนเซอร์ขนาดใหญ่ ที่ป้อนข้อมูลอนุกรมเวลาจำนวนมาก ทั้งในแง่ของประมาณ (Volume) และความเร็วในเพิ่มขึ้นของจำนวนข้อมูล (Velocity)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ในแง่ของการนำข้อมูลไปวิเคราะห์&lt;&#x2F;strong&gt;  ในระบบแบบเดิมยังต้อง export ข้อมูลออกไปยังโปรแกรมวิเคราะห์เช่น R, SPSS ซึ่งทำให้การขั้นตอนการทำงานยุ่งยาก&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ในแง่ของการจัดเก็บและเรียกดู ประสิทธิภาพของระบบยังคงต้องดี&lt;&#x2F;strong&gt; เมื่อข้อมูลมีขนาดใหญ่  ซึ่ง TSMS ก็เข้ามาช่วยตอบโจทย์ตรงนี้&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;หลายๆ คนอาจจะสงสัยว่าแล้วที่บอกว่าข้อมูลอนุกรมขนาดใหญ่นี้ มันใหญ่ขนาดไหนถึงต้องไปใช้ฐานข้อมูลอนุกรมเวลา ตรงนี้ผมขอยกตัวอย่างงานวิจัยของ Facebook ครับ
โดยเค้าต้องการ จะทำ server สำหรับ monitor ข้อมูลของทุก cluster ของ Facebook ครับ&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งโจทย์คือต้องสามารถตรวจสอบความผิดปกติได้อย่างรวดเร็ว ดังนั้นเค้าจึงออกแบบฐานข้อมูลอนุกรมเวลาที่อยู่บนแรมครับที่ชื่อว่า &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.vldb.org&#x2F;pvldb&#x2F;vol8&#x2F;p1816-teller.pdf&quot;&gt;Gorilla&lt;&#x2F;a&gt; เพื่อให้ต้องการ monitor แบบ real time ลองมามาดูโจทย์ของ Facebook กันครับ&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;มีข้อมูล 2 พันล้านอนุกรมเวลา&lt;&#x2F;li&gt;
&lt;li&gt;มีข้อมูลอนุกรมเวลา 700 ล้านจุดเข้ามาในระบบ ต่อนาที&lt;&#x2F;li&gt;
&lt;li&gt;เก็บข้อมูลย้อนหลังได้ 26 ชั่วโมง&lt;&#x2F;li&gt;
&lt;li&gt;รับโหลดสูงสุดได้ 40,000 query ต่อวินาที&lt;&#x2F;li&gt;
&lt;li&gt;สามารถอ่านข้อมูลได้อย่างรวดเร็ว&lt;&#x2F;li&gt;
&lt;li&gt;รองรับการโตของข้อมูล 2 เท่า ต่อปี&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;เป็นไงกันบ้างครับ ข้อมูลเยอะมากใช่มั้ย นี่คือตัวอย่างงานแบบ monitoring ถ้าเราไม่ต้องการ real time แบบนี้ ก็ไม่ต้องเก็บข้อมูลบนแรมก็ได้คับ โดยปกติจะเก็บของข้อมูลบน  Harddisk ขึ้นอยู่กับ requirements คับ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;มาถึงตรงนี้ แล้วฐานข้อมูลอนกรุมเวลาคืออะไร?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;ieeexplore.ieee.org&#x2F;document&#x2F;6427510&#x2F;&quot;&gt;ฐานข้อมูลแบบอนุกรมเวลา&lt;&#x2F;a&gt;  คือฐานข้อมูลที่ถูกพัฒนาและปรับปรุงมาเพื่อเก็บข้อมูลในงานทางด้านอนุกรมเวลาโดยเฉพาะ
ฐานข้อมูลแบบอนุกรมเวลาส่วนใหญ่แล้วจะถูกปรับแต่งให้เหมาะกับข้อมูลที่มีปริมาณมาก
และสามารถที่จะจัดเก็บจุดข้อมูลของอนุกรมเวลาและคำอธิบายเพิ่มเติมของข้อมูลนั้นๆ เท่านั้น&lt;&#x2F;p&gt;
&lt;p&gt;ดังนั้นฐานข้อมูลแบบอนุกรมเวลาสามารถจัดการข้อมูลแบบอนุกรมเวลาได้เหมาะสมกว่าฐานข้อมูลอเนกประสงค์ทั่วๆ ไป
เช่น ฐานข้อมูลแบบมีความสัมพันธ์ (Relational database) หรือฐานข้อมูลแบบไม่มีความสัมพันธ์ (Non-relational database)&lt;&#x2F;p&gt;
&lt;p&gt;อีกทั้งฐานข้อมูลแบบนี้ยังสามารถค้นหาข้อมูลแบบอนุกรมเวลา
เลื่อนช่วงของเวลาที่ต้องการสอบถาม รวมหลายๆ
อนุกรมเวลาเข้ามาเป็นหนึ่งอนุกรมเวลา หรือคำนวณเพื่อหาค่าของจุดที่หายไปของอนุกรมเวลา (interpolation)&lt;&#x2F;p&gt;
&lt;p&gt;ปัจจุบันยังไม่มีมาตรฐานการออกแบบและการเชื่อมต่อที่ชัดเจนที่จะอธิบายว่าฐานข้อมูลแบบอนุกรมเวลานั้นควรเป็นแบบไหน
และมีการเชื่อมต่ออย่างไร
หลายๆ องค์กรได้มีความพยายามที่จะสร้างฐานข้อมูลแบบอนุกรมเวลาสำหรับใช้ในองค์กร
ซึ่งแต่ละผู้พัฒนาได้ออกแบบความสามารถและ
API ของตนแตกต่างกันไป&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ฐานข้อมูลอนุกรมเวลาส่วนใหญ่แล้วมักจะมี 4 องค์ประกอบ คือ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;ส่วนของการเก็บข้อมูลอนุกรมเวลา&lt;&#x2F;li&gt;
&lt;li&gt;ส่วนของการเก็บเกี่ยวข้อมูล&lt;&#x2F;li&gt;
&lt;li&gt;ส่วนของการแสดงผล&lt;&#x2F;li&gt;
&lt;li&gt;ส่วนของการประมวลผลข้อมูล&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ซึ่งบางฐานข้อมูลอนุกรมเวลามีองค์ประกอบไม่ครบ
แต่ฐานข้อมูลเหล่านั้นมักอนุญาตให้เชื่อมต่อกับภายนอก
ยกตัวอย่างเช่น OpenTSDB มีส่วนของแสดงผลที่เหมาะสำหรับการใช้งานที่ไม่ซับซ้อน แต่
OpenTSDB
ก็สามารถเชื่อมต่อกับโปรแกรมประยุกต์เพื่อการแสดงผลอนุกรมเวลา เช่น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;grafana.com&#x2F;&quot;&gt;Grafana&lt;&#x2F;a&gt;
ได้
&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;bc4remlp4qcl27f&#x2F;2018-08-13-%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%B9%E0%B8%A5%E0%B8%AD%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B9%80%E0%B8%A7%E0%B8%A5%E0%B8%B2%20OpenTSDB%20%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-2.png?raw=1&quot; alt=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;bc4remlp4qcl27f&#x2F;2018-08-13-%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%B9%E0%B8%A5%E0%B8%AD%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B9%80%E0%B8%A7%E0%B8%A5%E0%B8%B2%20OpenTSDB%20%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-2.png?dl=0&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;grafana.com&#x2F;&quot;&gt;Grafana&lt;&#x2F;a&gt; คือ หน้าต่างอเนกประสงค์สำหรับแสดงผลข้อมูลอนุกรมเวลา
และมีส่วนขยายสำหรับการเชื่อมต่อกับ OpenTSDB อีกด้วย&lt;&#x2F;p&gt;
&lt;h3 id=&quot;taw-yaangkaar-query-kh-muulcchaakthaankh-muul-nukrmewlaa&quot;&gt;ตัวอย่างการ Query ข้อมูลจากฐานข้อมูลอนุกรมเวลา&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangkaar-query-kh-muulcchaakthaankh-muul-nukrmewlaa&quot; aria-label=&quot;Anchor link for: taw-yaangkaar-query-kh-muulcchaakthaankh-muul-nukrmewlaa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ประเภทงานส่วนใหญ่ของการใช้ฐานข้อมูลแบบอนุกรมเวลาคือการสอบถามข้อมูลอนุกรมเวลา
ฐานข้อมูลแบบอนุกรมเวลาส่วนใหญ่จะมีการออกแบบที่ทำให้สะดวกต่อการใช้ค้นหาตามช่วงของเวลา
สมมติว่า
เราต้องการสอบถามข้อมูลอุณหภูมิที่จัดเก็บไว้ในฐานข้อมูลอยู่ก่อนแล้วจากปีค.ศ. 2013
ถึง 2016
จากข้อมูลตัวอย่าง มีข้อมูลจำนวน 1 ล้านจุดต่อข้อมูลระยะเวลา 1 ปี
คำสั่งในการสอบถามมีลักษณะได้หลากหลายรูปแบบ
โดยรูปแบบข้างล่างนี้เป็นตัวอย่างอย่างง่ายในการสอบถามข้อมูล&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;QUERY temperature FROM 2013 TO 2016
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ผลลัพธ์การสอบถามจะเป็นในรูปแบบของอาร์เรย์ของจุดข้อมูล โดยผลลัพธ์จะมี 3
ล้านจุดข้อมูล
และผลลัพธ์ที่ได้ยังสามารถนำไปแสดงผลเป็นกราฟอนุกรมเวลา&lt;&#x2F;p&gt;
&lt;p&gt;ฐานข้อมูลแบบอนุกรมเวลาแบบ Open Source ที่ได้รับความนิยม เช่น OpenTSDB, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;kairosdb.github.io&#x2F;&quot;&gt;KairosDB&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.influxdata.com&#x2F;&quot;&gt;InfluxDB&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;prometheus.io&#x2F;&quot;&gt;Prometheus&lt;&#x2F;a&gt; และ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.elastic.co&#x2F;products&#x2F;elasticsearch&quot;&gt;Elasticsearch&lt;&#x2F;a&gt; จริงๆ ก็มีอีกหลายตัวที่ไม่ได้ยกตัวอย่างมาครับ&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;saamaarthsueksaaephimetimaidnakhrab&quot;&gt;สามารถศึกษาเพิ่มเติมได้นะครับ&lt;a class=&quot;zola-anchor&quot; href=&quot;#saamaarthsueksaaephimetimaidnakhrab&quot; aria-label=&quot;Anchor link for: saamaarthsueksaaephimetimaidnakhrab&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;ieeexplore.ieee.org&#x2F;document&#x2F;8012550&#x2F;&quot;&gt;Time Series Management Systems: A Survey&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.influxdata.com&#x2F;time-series-database&#x2F;&quot;&gt;Time Series Database (TSDB) Explained&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;blog.timescale.com&#x2F;what-the-heck-is-time-series-data-and-why-do-i-need-a-time-series-database-dcf3b1b18563&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;blog.timescale.com&#x2F;time-series-data-why-and-how-to-use-a-relational-database-instead-of-nosql-d0cd6975e87c&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;github.com&#x2F;xephonhq&#x2F;awesome-time-series-database&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ไว้พบกันใหม่โอกาสหน้าครับ สวัสดีครับ&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Cross published at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@mildronize&#x2F;%E0%B8%97%E0%B8%B3%E0%B9%84%E0%B8%A1%E0%B9%80%E0%B8%A3%E0%B8%B2%E0%B8%96%E0%B8%B6%E0%B8%87%E0%B8%84%E0%B8%A7%E0%B8%A3%E0%B9%83%E0%B8%8A%E0%B9%89%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%B9%E0%B8%A5%E0%B8%AD%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B9%80%E0%B8%A7%E0%B8%A5%E0%B8%B2%E0%B8%AA%E0%B8%B3%E0%B8%AB%E0%B8%A3%E0%B8%B1%E0%B8%9A-%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%B9%E0%B8%A5%E0%B8%AD%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B9%80%E0%B8%A7%E0%B8%A5%E0%B8%B2-time-series-database-d524d25060ec&quot;&gt;Medium.com&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>เขียนบล็อกด้วยภาษา Markdown ด้วยแอพจดโน๊ต Bear บน iOS</title>
		<published>2018-07-20T00:00:00+00:00</published>
		<updated>2018-07-20T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/create-blog-with-markdown-and-bear-note-on-ios-th/" type="text/html"/>
		<id>https://thadaw.com/posts/create-blog-with-markdown-and-bear-note-on-ios-th/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;ย้าย blog กลับมาใช้ Jekyll เหมือนเดิมแล้วคับ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;เนื่องจากผมเอง&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;mildronize.github.io&quot;&gt;เขียน blog&lt;&#x2F;a&gt; กับ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.staticgen.com&quot;&gt;Static page generator&lt;&#x2F;a&gt; ซึ่งใช้ภาษา Markdownในการเขียนเนื้อหา ซึ่งใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;jekyllrb.com&quot;&gt;Jekyll&lt;&#x2F;a&gt; ในในการแปลงเป็นหน้าเว็บให้ เลยหาเครื่องมือหาเหมาะๆ ที่ไม่ต้องอยู่หน้าคอม แล้วมานั่งเขียนบล็อก อยากแบบเขียนช่วงว่างๆ ตาม มุมพักผ่อนต่างๆ ที่ไม่ต้องพกโน๊ตบุ๊คไปด้วยคับ ( ไว้มีโอกาสจะเขียน เรื่อง Static page generator อีกบล็อกครับ)&lt;&#x2F;p&gt;
&lt;p&gt;เลยลองหาแอพที่เอาไว้ใช้เขียน blog ดูว่าตัวไหนดีและฟรีบ้าง ก็มาเจอ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.bear-writer.com&quot;&gt;Bear&lt;&#x2F;a&gt; นี่แหละครับ จริงๆ bear เป็น แอพไว้จดโน๊ตอารมณ์เดียวกับ Evernote นั่นแหละครับ
&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;ctdl5fr7c7cplbb&#x2F;2018-07-20-%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B8%9A%E0%B8%A5%E0%B9%87%E0%B8%AD%E0%B8%81%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2%20Markdown%20%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B9%81%E0%B8%AD%E0%B8%9E%E0%B8%88%E0%B8%94%E0%B9%82%E0%B8%99%E0%B9%8A%E0%B8%95%20Bear%20%E0%B8%9A%E0%B8%99%20iOS-0.jpg?raw=1&quot; alt=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;ctdl5fr7c7cplbb&#x2F;2018-07-20-%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B8%9A%E0%B8%A5%E0%B9%87%E0%B8%AD%E0%B8%81%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2%20Markdown%20%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B9%81%E0%B8%AD%E0%B8%9E%E0%B8%88%E0%B8%94%E0%B9%82%E0%B8%99%E0%B9%8A%E0%B8%95%20Bear%20%E0%B8%9A%E0%B8%99%20iOS-0.jpg?dl=0&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kh-diikh-ng-bear-thiithamaihphmch-bmaak-khuue&quot;&gt;ข้อดีของ Bear ที่ทำให้ผมชอบมากๆ คือ&lt;a class=&quot;zola-anchor&quot; href=&quot;#kh-diikh-ng-bear-thiithamaihphmch-bmaak-khuue&quot; aria-label=&quot;Anchor link for: kh-diikh-ng-bear-thiithamaihphmch-bmaak-khuue&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Bear คือแอพจดโน๊ตที่รวมกับ Markdown ได้อย่างแนบเนียน ไม่เหมือนกับอารมณ์เขียน Markdown ทั่วๆ ไป&lt;&#x2F;li&gt;
&lt;li&gt;สามารถใช้ร่วมกับ Markdown ได้ดีเลยครับ&lt;&#x2F;li&gt;
&lt;li&gt;มี syntax blockquote แบบไว้แนบโค๊ดได้เลย ไม่ต้องไปฝากไว้ที่ gist ของ github&lt;&#x2F;li&gt;
&lt;li&gt;สามารถเห็นรูปภาพในการเขียนโน๊ตได้เลยครับ ทำให้มองเห็นภาพได้เลยขณะพิมพ์ ไม่จำเป็นต้องกด preview ดูผลลัพธ์ครับ พูดง่ายๆ เป็น WYSIWYG ครับ&lt;&#x2F;li&gt;
&lt;li&gt;เป็นแอพที่สามารถใช้งานร่วมกับแอพอื่นๆ หรือ platform อื่นๆ ได้ดีครับ คือสามารถ export ออกเป็นไฟล์ Markdown พร้อมกับมีโฟลเดอร์รูปภาพซึ่งสามารถไปใช้กับ Markdown editor ทั่วๆ ไปได้เลยครับ ( รูปแบบนี้ Bear เรียกว่า Text Bundle )&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;สุดท้ายที่ชอบมากๆ&lt;&#x2F;strong&gt; คือ สามารถใส่แท็กแบบ inline ได้เลยแบบ ไม่ต้องไปกดปุ่มใดๆ เพิ่มเติมเลย และสามารถสร้างลิงค์ไปโน๊ตอันอื่นๆ ได้ด้วย ซึ่ง&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ส่วนข้อเสียก็มีแค่ให้ใช้ในตระกูลของ Apple เพียงอย่างเดียวครับ แต่สามารถ export เป็น Markdown ปกติได้ แบบนี้ให้อภัยได้&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ruupphaaphcchaekb-yaangair&quot;&gt;รูปภาพจะเก็บอย่างไร ?&lt;a class=&quot;zola-anchor&quot; href=&quot;#ruupphaaphcchaekb-yaangair&quot; aria-label=&quot;Anchor link for: ruupphaaphcchaekb-yaangair&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;mildronize.github.io&quot;&gt;blog ที่ใช้ Jekyll&lt;&#x2F;a&gt; นั้นอัพโหลดรูปภาพเป็น ไฟล์ที่อยู่ static ของ git repo ครับ ซึ่งมันไม่สะดวกเอามากๆ และเกิดความลำบากในการย้ายบล็อกในอนาคต
แล้ว git repo เองก็มีข้อจำกัดในเรื่องของ&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;help.github.com&#x2F;articles&#x2F;what-is-my-disk-quota&#x2F;&quot;&gt;พื้นที่ที่สามารถใช้งานได้ประมาณ 1 GB&lt;&#x2F;a&gt; ครับ&lt;&#x2F;p&gt;
&lt;p&gt;ต่อไปก็มองหาที่เก็บรูปภาพแบบถาวรที่สามารถเอาลิงค์ตรงมาใส่ใน html ได้ ซึ่งตอนแรกตั้งใจว่าจะเก็บใน imgur แต่ไม่แน่ใจว่าจะเก็บถาวรมั้ย จาก&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.quora.com&#x2F;Imgur-How-long-are-the-images-stored-before-being-purged&quot;&gt;ที่เค้าคุยกันในกระทู้บอกว่า imgur จะเก็บถาวร&lt;&#x2F;a&gt; และอีกอย่างคงจัดการได้ยาก&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ทางออกคือ Dropbox&lt;&#x2F;strong&gt; เป็น cloud storage ชื่อดังเจ้าเดียวเท่าที่ผมรู้จัก ( Box, Google Drive, OneDrive และ iCloud ทำไม่ได้ครับ) ที่สามารถเข้าถึง direct link ของรูปภาพได้ โดยแค่เปลี่ยนคำลงท้าย url จาก &lt;code&gt;dl=0&lt;&#x2F;code&gt; เป็น &lt;code&gt;raw=1&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kaarbrihaarcchadkaarontain-bear-samhrabekhiiynbl-k&quot;&gt;การบริหารจัดการโน๊ตใน Bear สำหรับเขียนบล็อก&lt;a class=&quot;zola-anchor&quot; href=&quot;#kaarbrihaarcchadkaarontain-bear-samhrabekhiiynbl-k&quot; aria-label=&quot;Anchor link for: kaarbrihaarcchadkaarontain-bear-samhrabekhiiynbl-k&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ผมใช้ tag ทั้งสิ้น 3 แบบครับ&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;blog&#x2F;draft&lt;&#x2F;code&gt; สำหรับเขียนร่างบล็อก&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;blog&#x2F;publish&lt;&#x2F;code&gt; สำหรับ blog ที่เผยแพร่แล้ว&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;blog&#x2F;template&lt;&#x2F;code&gt; สำหรับ template markdown ที่จะใช้ในการเขียน blog บน GatsbyJS ครับ&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ส่วน template ที่ใช้ในการเขียนบล็อก
&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;7dvcxre78kq2toi&#x2F;2018-07-20-%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B8%9A%E0%B8%A5%E0%B9%87%E0%B8%AD%E0%B8%81%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2%20Markdown%20%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B9%81%E0%B8%AD%E0%B8%9E%E0%B8%88%E0%B8%94%E0%B9%82%E0%B8%99%E0%B9%8A%E0%B8%95%20Bear%20%E0%B8%9A%E0%B8%99%20iOS-1.jpeg?raw=1&quot; alt=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;7dvcxre78kq2toi&#x2F;2018-07-20-%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B8%9A%E0%B8%A5%E0%B9%87%E0%B8%AD%E0%B8%81%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2%20Markdown%20%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B9%81%E0%B8%AD%E0%B8%9E%E0%B8%88%E0%B8%94%E0%B9%82%E0%B8%99%E0%B9%8A%E0%B8%95%20Bear%20%E0%B8%9A%E0%B8%99%20iOS-1.jpeg?dl=0&quot; &#x2F;&gt;
และเมื่อ export เป็น Text Bundle ที่เป็นภาษา Markdown ดังนี้ครับ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;markdown&quot; class=&quot;language-markdown z-code&quot;&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-block-level z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-heading z-1 z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-begin z-markdown&quot;&gt;#&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-heading z-1 z-markdown&quot;&gt;&lt;span class=&quot;z-entity z-name z-section z-markdown&quot;&gt;Template ชื่อบล็อก&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-whitespace z-newline z-markdown&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-block-level z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-separator z-thematic-break z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-thematic-break z-markdown&quot;&gt;---&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-markdown&quot;&gt;title: &amp;quot;เขียนบล็อกด้วยภาษา Markdown ด้วยแอพจดโน๊ต Bear บน iOS&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-markdown&quot;&gt;date: &amp;quot;7&#x2F;20&#x2F;2018&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-markdown&quot;&gt;tags:
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-markdown&quot;&gt;	* Bear
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-heading z-2 z-setext z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-setext z-markdown&quot;&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-block-level z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-heading z-1 z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-begin z-markdown&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-heading z-1 z-markdown&quot;&gt;&lt;span class=&quot;z-entity z-name z-section z-markdown&quot;&gt;blog&#x2F;draft&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-whitespace z-newline z-markdown&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-markdown&quot;&gt;&lt;span class=&quot;z-meta z-paragraph z-markdown&quot;&gt;&lt;span class=&quot;z-markup z-bold z-markdown&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-bold z-begin z-markdown&quot;&gt;**&lt;&#x2F;span&gt;Remove this tag&lt;span class=&quot;z-punctuation z-definition z-bold z-end z-markdown&quot;&gt;**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; #blog&#x2F;template
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;t-aippramwlphlaifl-aela-aphohldruupkhuen-dropbox-dwyae-ph-shortcuts&quot;&gt;ต่อไปประมวลผลไฟล์ และอัพโหลดรูปขึ้น dropbox ด้วยแอพ Shortcuts&lt;a class=&quot;zola-anchor&quot; href=&quot;#t-aippramwlphlaifl-aela-aphohldruupkhuen-dropbox-dwyae-ph-shortcuts&quot; aria-label=&quot;Anchor link for: t-aippramwlphlaifl-aela-aphohldruupkhuen-dropbox-dwyae-ph-shortcuts&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;7dranoizgn7ph78&#x2F;2018-07-20-%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B8%9A%E0%B8%A5%E0%B9%87%E0%B8%AD%E0%B8%81%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2%20Markdown%20%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B9%81%E0%B8%AD%E0%B8%9E%E0%B8%88%E0%B8%94%E0%B9%82%E0%B8%99%E0%B9%8A%E0%B8%95%20Bear%20%E0%B8%9A%E0%B8%99%20iOS-2.jpg?raw=1&quot; alt=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;7dranoizgn7ph78&#x2F;2018-07-20-%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B8%9A%E0%B8%A5%E0%B9%87%E0%B8%AD%E0%B8%81%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2%20Markdown%20%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B9%81%E0%B8%AD%E0%B8%9E%E0%B8%88%E0%B8%94%E0%B9%82%E0%B8%99%E0%B9%8A%E0%B8%95%20Bear%20%E0%B8%9A%E0%B8%99%20iOS-2.jpg?dl=0&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ตั้งแต่รู้จักกับแอพ Shortcuts นี้รู้สึกชีวิตจะสะดวกสบายหลายอย่าง มันช่วยมันง่ายที่เราต้องทำซ้ำๆ บ่อยให้เรา ก็เหมือนกับการเขียนโปรแกรมนั่นแหละคับ แต่มันจะเป็นการลากบล็อก ( อารมณ์เหมือน module ที่มี input และ output ) มาเรียงต่อกันเป็นชุดคำสั่งครับ
ทำให้เราสามารถทำ automation ง่ายๆ ได้ครับ&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ain-shortcuts-publish-bear-note-to-markdown-tham-aairbaang&quot;&gt;ใน Shortcuts: Publish bear note to markdown ทำอะไรบ้าง&lt;a class=&quot;zola-anchor&quot; href=&quot;#ain-shortcuts-publish-bear-note-to-markdown-tham-aairbaang&quot; aria-label=&quot;Anchor link for: ain-shortcuts-publish-bear-note-to-markdown-tham-aairbaang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;ขอสิทธิ์การเขียนไฟล์ลงบน Dropbox ในทีนี้ผมตั้งค่าให้เก็บไฟล์รูปที่ &lt;code&gt;&#x2F;Public&#x2F;blog&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ใส่ชื่อของโน๊ตลงไปใน &lt;code&gt;[POST_TITLE]&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ใส่วันที่ปัจจุบันลงไปใน &lt;code&gt;[TITLE]&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;อัพโหลดรูปขึ้น dropbox ทุกรูป แล้วแก้ url ให้เป็น direct link&lt;&#x2F;li&gt;
&lt;li&gt;จากนั้นแก้รูปแบบให้ตรงกับ yaml frontmatter เป็นอันเสร็จ&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;khant-nkaarnamaipaich&quot;&gt;ขั้นตอนการนำไปใช้&lt;a class=&quot;zola-anchor&quot; href=&quot;#khant-nkaarnamaipaich&quot; aria-label=&quot;Anchor link for: khant-nkaarnamaipaich&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;เตรียมแอพที่เกี่ยวข้อง Bear, Shortcuts, Git2Go และ account dropbox&lt;&#x2F;li&gt;
&lt;li&gt;ดาวน์โหลด Shortcuts  &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;workflow.is&#x2F;workflows&#x2F;de83eed7d725415dac37d35b46ce946e&quot;&gt;publish bear note to markdown&lt;&#x2F;a&gt; ไปใช้&lt;&#x2F;li&gt;
&lt;li&gt;เขียน Blog ด้วย bear โดยใช้ template ข้างบน หรือกำหนด template เองก็ได้&lt;&#x2F;li&gt;
&lt;li&gt;ลบข้อความ &lt;code&gt;**Remove this tag** &lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;กดไปที่ Export as ในเมนู แล้วเลือก Text Bundle&lt;&#x2F;li&gt;
&lt;li&gt;เลือก Run as Workflow&lt;&#x2F;li&gt;
&lt;li&gt;เลือก &lt;code&gt;Publish bear note to markdown &lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;เลือกแอพที่จะเผยแพร่ ในที่นี้ผมใช้ Git2Go ในการเผยแพร่คับ&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Download &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;workflow.is&#x2F;workflows&#x2F;de83eed7d725415dac37d35b46ce946e&quot;&gt;publish bear note to markdown&lt;&#x2F;a&gt;
Read more at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;mildronize&#x2F;1da2120b1d2f0a25a7ecc429c06d3dce&quot;&gt;my gist&lt;&#x2F;a&gt;
P.S. For English version, I will write later.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Cross published at &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@mildronize&#x2F;%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B8%9A%E0%B8%A5%E0%B9%87%E0%B8%AD%E0%B8%81%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2-markdown-%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B9%81%E0%B8%AD%E0%B8%9E%E0%B8%88%E0%B8%94%E0%B9%82%E0%B8%99%E0%B9%8A%E0%B8%95-bear-%E0%B8%9A%E0%B8%99-ios-d85908c2cea5&quot;&gt;Medium.com&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>การเขียนงานวิจัยประชุมวิชาการครั้งแรก</title>
		<published>2018-04-09T00:00:00+00:00</published>
		<updated>2018-04-09T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/my-first-conference-paper/" type="text/html"/>
		<id>https://thadaw.com/posts/my-first-conference-paper/</id>
		<content type="html">&lt;p&gt;ขอบันทึกการเดินทาง งานวิจัย หน่อย กว่าจะออกเป็น เปเปอร์ของตัวเองอันแรก&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;my-first-conference-paper&#x2F;my-paper.jpg&quot; alt=&quot;my paper&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ตั้งแต่เริ่มเรียนป.โท ละ ตอนนี้ก็ปี จะครบปีที่ 3 แล้ว&lt;&#x2F;p&gt;
&lt;p&gt;ใช้เวลา 1 เทอมสำหรับการอ่านงานวิจัยคนอื่น แล้วก็เปลี่ยนเรื่องที่จะทำจากหน้ามือเป็นหลังมือ จากจะทำเรื่อง game sever มาเป็น cache บน database&lt;&#x2F;p&gt;
&lt;p&gt;ใช้เวลา 1 เทอม กว่าๆ สำหรับชีวิตในค่ายทหาร ที่ตัดสินใจสมัครทหารไป รู้สึกว่าตัวเองคิดไม่ผิด เสมอมา เพราะทุกอย่างที่เกิดขึ้นล้วนดีเสมอ&lt;&#x2F;p&gt;
&lt;p&gt;ตั้งแต่ออกจากค่ายทหารมา ก็ได้รับโจทย์ที่ท้าทาย อย่างนึงคือ จบให้ทันภายใน เดือน ก.ค. หรือ เวลา 6 เดือน กับความก้าวหน้าของงานอันน้อยนิด ถ้าจะแผนเดิมคือ จะใช้ เวลา 1 ปี กว่าจะจบ&lt;&#x2F;p&gt;
&lt;p&gt;ปรับเป้าหมายใหม่ มีพันธสัญญากับตัวเอง ต้องทำงานดีขึ้นในทุกๆ วัน ตัวเองต้องมีการพํฒนา ใช้เวลาให้คุ้ม ใช้เวลากับการทำงาน แบบ work smart มากกว่าแบบ work hard ซึ่งโดยส่วนตัว เป็นคนประเภท work hard คือลุย ทำอย่างหนัก วันนึงอยู่หน้าจอคอม 14-16 ชม. ด้วยความ perfectionist ของตัวเอง เลยต้องปรับแก้ตัวเองใหม่&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งตั้งแต่ออกจากค่ายทหาร ต้องเขียนโปรแกรมไปต่อยอดงานคนอื่น หรือในรูป คือ OpenTSDB ซึ่งเป็นโปรเจ็คใหญ่มาก เขียนด้วย java 50 Classes + 30k line of code + Unit test อีกนับไม่ถ้วน เคยรัน unit test ทั้งระบบ ใช้เวลา ชมกว่า ดังนั้นถ้าแก้โปรแกรมที่รัน unitest ทั้งหมด คงรอกันตายเลย&lt;&#x2F;p&gt;
&lt;p&gt;ปัญหาใหญ่ๆ คือ การหาจุดที่จะลงไปแก้ปัญหาในงานคนอื่นนี่แหละ เพราะก่อนหน้านี้เวลา เทอมกว่าๆ 5-6 เดือนในการหาว่า ตรงไหนจะลงไปแก้ แต่ก็หาไม่เจอ ด้วยความที่ ทักษะ การเขียนโปรแกรมด้วย java หายไป 3-4 ปี กับไม่เคยเจอโปรเจ็คใหญ่ขนาดนี้ เลยทำให้หลงทางบ่อยมาก&lt;&#x2F;p&gt;
&lt;p&gt;สิ่งที่รู้สึก amazing กับตัวเอง คือ หลังจากออกจากค่ายทหารมา ใช้เวลาแค่ 2 สัปดาห์ในการหาว่าจุดไหน เราจะลงไปแก้ปัญหาให้เขา ทั้งๆ ที่ก่อนหน้า หาอยู่ 5-6 เดือน เพราะความมีพันธสัญญาตัวเองจริงๆ เราตั้งใจมากขึ้น work smart คิด วางแผน เดินช้าๆ แต่ถูกทาง ก่อนหน้านี้คือเดินเร็ว แต่ผิดทาง&lt;&#x2F;p&gt;
&lt;p&gt;ใช้เวลา 5 สัปดาห์ เขียนโปรแกรม พร้อม unitest และก็แก้บัคอยู้ 3-4 สัปดาห์ กว่า ผลการทำงานครั้งแรกจะออกมา&lt;&#x2F;p&gt;
&lt;p&gt;หลังจากนั้นวางแผนจะส่งงานประชุมวิชาการ เพราะต้องส่ง ไม่งั้นจะจบไม่ทัน เลยเตรียมตัวจะส่ง เขียนโปรแกรมสำหรับรันผลการทดลอง อีกนาน 2-3 สัปดาห์ เพื่อให้คอมทำงานให้เราทั้งหมด แต่พบปัญหารายทางตลอด เกิดจากความไม่รอบคอบ และเร่งรีบเกินไป ต่อเป้าหมาย (เนื่องจากรันผลหลังกรณีมาก จำนวนของ start ระบบ เทส และทำลาย น่าจะวนๆ อยู่ที่ 1000 รอบ ถ้าทำเองก็คงเดี้ยงซะก่อน 555+)&lt;&#x2F;p&gt;
&lt;p&gt;จากการทำงานอย่างหนักหน่วงในช่วง 3-4 วันนี้ (ไม่ได้เพิ่งมาเร่งทีหลังนะ แต่ผลการทดลองยังเอาไปเขียนงานไม่ได้ ต้องแก้โปรแกรมกันหลายรอบ) จนถึง ตี 3 ของวันที่ 9 เมษา ส่งงานเรียบร้อย เป็นงานประชุมวิชาการระดับนานาชาติ ซึ่ง deadline คือ 9 โมงเช้า&lt;&#x2F;p&gt;
&lt;p&gt;ถึงแม้ว่ายังเป็นแค่ candidate paper แต่เราก็ลุยสุดๆ ทำเต็มที่แล้วผลลัพธ์ที่ได้ออกมาจะเป็นยังไงก็ไม่สนใจแล้ว&lt;&#x2F;p&gt;
&lt;p&gt;ขอขอบคุณ อาจารย์ที่ปรึกษา อาจารย์ Pichaya Tandayya มากๆ ที่ลุยกันถึงช่วงโค้งสุดท้าย&lt;&#x2F;p&gt;
&lt;p&gt;Cross Publish at Facebook &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.facebook.com&#x2F;photo?fbid=10216470924033685&amp;amp;set=a.1962315945623&quot;&gt;https:&#x2F;&#x2F;www.facebook.com&#x2F;photo?fbid=10216470924033685&amp;amp;set=a.1962315945623&lt;&#x2F;a&gt; (Sorry this link is not public)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>การเดินทางของ Xiaomi Mi2s และแนวทางแก้ปัญหาเซนเซอร์แนบหู (Proximity Sensor) ไม่ทำงาน</title>
		<published>2017-01-29T00:00:00+00:00</published>
		<updated>2017-01-29T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/my-xiaomi-mi2s-journey/" type="text/html"/>
		<id>https://thadaw.com/posts/my-xiaomi-mi2s-journey/</id>
		<content type="html">&lt;p&gt;ผมซื้อเจ้า &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.gsmarena.com&#x2F;xiaomi_mi_2s-5397.php&quot;&gt;Xiaomi Mi2s&lt;&#x2F;a&gt; เมื่อวันที่ 11 กรกฎาคม 2556 ถ้านับเวลาจากวันนั้นถึงวันนี้ก็รวมๆ แล้ว 3 ปีครึ่งที่อยู่บนมือผม มือถือเครื่องนี้เป็นมือถือเครื่องที่ 3 ในชีวิตผมล่ะ เครื่องแรกก็ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.gsmarena.com&#x2F;sony_ericsson_w200-1824.php&quot;&gt;Sony Ericsson W200i&lt;&#x2F;a&gt; ในสมัยนั้นยังไม่มี smart phone อะไรเลย กว่าราคามือถือที่สามารถฟังเพลงได้ ถ่ายรูปได้ ราคาจะลงมาในระดับที่เด็กนักเรียนคนนึงสามารถเก็บเงินซื้อได้ ตอนนั้นซื้อราคา 4 พันกว่าๆ&lt;&#x2F;p&gt;
&lt;p&gt;เครื่องที่สองคือ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.gsmarena.com&#x2F;motorola_defy-3514.php&quot;&gt;Motorola Defy&lt;&#x2F;a&gt; เป็น smart phone เครื่องแรกๆ ที่สามารถกันน้ำได้ ตอนนั้นเพิ่งเข้าไทยใหม่ๆ ผมเลยซื้อมาเลย เครื่องนี้นับว่าผ่านร้อน ผ่านหนาวมาเยอะเหมือนกัน เปลี่ยนแบตเตอร์รี่ไป 1 รอบ เปลี่ยนหน้าจอสัมผัสไปแล้วน่าจะสัก 4-5 รอบได้ สั่งมาเปลี่ยนเอง จนแทบหาอะไหล่แทบไม่ได้ ผนวกกับ ROM แทบจะอัพเกรดไปต่อไปไม่ไหวแล้ว ตอนที่ซื้อมาเป็น Android 2.1 อัพเกรดโดยใช้ Custom ROM (สมัยนั้นก็มี &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;en.miui.com&#x2F;&quot;&gt;MIUI&lt;&#x2F;a&gt; 3, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;CyanogenMod&quot;&gt;CyanogenMod&lt;&#x2F;a&gt; 7) มาเรื่อยๆจนถึง Android 4.0 ก็มาจบที่ CyanogenMod 7 ในที่สุดก็ได้วางเครื่องนั้นไปแล้วไปซื้อเจ้า Xiaomi Mi2s&lt;&#x2F;p&gt;
&lt;p&gt;เครื่องต่อไปก็ Xiaomi Mi2s เนี่ยแหละ เครื่องประวัติก็ไม่ธรรมดา&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;เปลี่ยนแบตเตอร์รี่ไป 2 รอบแล้ว&lt;&#x2F;li&gt;
&lt;li&gt;เปลี่ยนหน้าจอสัมผัสไปแล้ว 2 รอบ&lt;&#x2F;li&gt;
&lt;li&gt;ส่งซ่อมเฉพาะรูสำหรับชาร์จไฟ (Micro usb) เพราะว่าของเดิมมันหลวมจนเสียบสายชาร์จไม่ได้&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ปัญหาคือ รอบแรกที่เปลี่ยนหน้าจอสัมผัสกับร้านรับซ่อมมือถือร้านหนึ่งใน กทม. แต่พอเอามาใช้งานกลับปรากฏว่า Proximity Sensor พัง (เซนเซอร์ที่มีหน้าที่ตรวจจับการแนบหู เวลาโทรถ้าแนบหูแล้ว หน้าจอจะดับ) ใช้งานไม่ได้&lt;&#x2F;p&gt;
&lt;p&gt;ปัญหาเวลาใช้งานโทรศัพทคือ เวลาโทรจอดับตลอดเวลา คือเซนเซอร์เข้าใจว่า มือถือแนบหูตลอดเวลา เลยทำให้วางสายหรือสัมผัสหน้าจออะไรไม่ได้จนกระทั่งอีกฝั่งต้องวางสายก่อน ซึ่งก็ลำบากเลยทีเดียว&lt;&#x2F;p&gt;
&lt;p&gt;ตอนแรกแก้ปัญหาโดยใข้ Feature ปิดเซนเซอร์ Proximity Sensor ของแอพ Phone ของรอม MIUI ปัญหาคือ ถ้าเราโทรผ่านแอพ Line หรือ Messenger ก็ยังคงมีปัญหาเดิมอยู่ ผนวกกับมือถือเก่าละ รอมที่ใช้อยู่ เป็น MIUI 8 มันทำงานช้าลง เลยตัดสินใจเปลี่ยนเป็นรอม CyanogenMod 12.1 (Android 5.1) เลยต้องใช้ตัวช่วยอย่าง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;repo.xposed.info&#x2F;module&#x2F;com.mrchandler.disableprox&quot;&gt;Sensor Disabler&lt;&#x2F;a&gt; ซึ่งจำเป็นต้องติดตั้ง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;repo.xposed.info&#x2F;module&#x2F;de.robv.android.xposed.installer&quot;&gt;Xposed Framework&lt;&#x2F;a&gt; เพื่อที่จะปิดการทำงานของ Proximity Sensor และเครื่องนั้นจะต้อง root ด้วย&lt;&#x2F;p&gt;
&lt;h2 id=&quot;srupepnkhant-ndangnii&quot;&gt;สรุปเป็นขั้นตอนดังนี้&lt;a class=&quot;zola-anchor&quot; href=&quot;#srupepnkhant-ndangnii&quot; aria-label=&quot;Anchor link for: srupepnkhant-ndangnii&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;ติดตั้ง Custom ROM&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;ติดตั้ง Custom Recovery ในที่นี้ผมใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;twrp.me&#x2F;&quot;&gt;TWRP&lt;&#x2F;a&gt; &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;en.miui.com&#x2F;thread-190608-1-1.html&quot;&gt;ลิงค์สำหรับ Mi2s&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ติดตั้ง CyanogenMod 12.1 ผ่าน TWRP Recovery ซึ่งผมใช้&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;en.miui.com&#x2F;thread-140138-1-1.html&quot;&gt;ไฟล์นี้&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ติดตั้ง Google App โดยดาวโหลดจาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;opengapps.org&#x2F;&quot;&gt;OpenGapps.org&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ถ้ามีปัญหาไม่สามารถเปิดกล้องได้ ลองติดตั้ง&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;forum.xda-developers.com&#x2F;galaxy-s3&#x2F;themes-apps&#x2F;17-fixed-camera-app-lib-cm-aosp-roms-t2505973&quot;&gt;ตัวแก้&lt;&#x2F;a&gt; โดยติดตั้งผ่าน TWRP Recovery เช่นกัน&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;Root เครื่อง&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;ติดตั้ง Supersu ผ่าน TWRP Recovery โดยดาวโหลดจาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;download.chainfire.eu&#x2F;696&#x2F;supersu&#x2F;&quot;&gt;Chainfire.eu&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;ติดตั้ง Xposed Framework&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;ติดตั้ง Xposed Framework โดยวิธีติดตั้งดูจากเว็บ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;forum.xda-developers.com&#x2F;showthread.php?t=3034811&quot;&gt;Xposed Offical XDA forum&lt;&#x2F;a&gt; ซึ่งสำหรับ Lollipop&#x2F;Marshmallow เท่านั้น&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;ปิดการทำงานของ Proximity Sensor&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;ติดตั้ง &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;repo.xposed.info&#x2F;module&#x2F;com.mrchandler.disableprox&quot;&gt;Sensor Disabler&lt;&#x2F;a&gt; ผ่านทางแอพ Xposed installer ที่ลงจากขั้นตอนที่แล้ว จากนั้น มี enable module นี้แล้วให้ Restart เครื่องหนึ่งครั้งถึงจะใช้งานได้&lt;&#x2F;li&gt;
&lt;li&gt;เข้าแอพ Sensor Disabler จากนั้นไปเลือก Proximity Sensor จากเมนูเลือกค่าเป็น 5 นั่นคือบังคับค่าให้เซนเซอร์ตรวจว่า ไม่ได้แนบหูอยู่ตลอดเวลานั้นเอง&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ก็เสร็จสิ้นไว้เพียงเท่านี้ รายละเอียดขั้นตอนการทำงานมันเยอะ ถ้าอยากสอบถามขั้นตอนไหน ทิ้งข้อความในคอนเม้นต์ด้านล่างได้เลยครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>A very short Ubuntu&#x2F;Debian packages installation sheet</title>
		<published>2016-11-21T00:00:00+00:00</published>
		<updated>2016-11-21T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/a-very-short-ubuntu-debian-packages-installation/" type="text/html"/>
		<id>https://thadaw.com/posts/a-very-short-ubuntu-debian-packages-installation/</id>
		<content type="html">&lt;h2 id=&quot;docker&quot;&gt;Docker&lt;a class=&quot;zola-anchor&quot; href=&quot;#docker&quot; aria-label=&quot;Anchor link for: docker&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.docker.com&#x2F;engine&#x2F;installation&#x2F;linux&#x2F;ubuntulinux&#x2F;&quot;&gt;Install on Ubuntu&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.docker.com&#x2F;engine&#x2F;installation&#x2F;linux&#x2F;debian&#x2F;&quot;&gt;Install on Debian&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;google-chrome&quot;&gt;Google Chrome&lt;a class=&quot;zola-anchor&quot; href=&quot;#google-chrome&quot; aria-label=&quot;Anchor link for: google-chrome&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; wget&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;q&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;O&lt;&#x2F;span&gt; - https:&#x2F;&#x2F;dl.google.com&#x2F;linux&#x2F;linux_signing_key.pub&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; apt-key add -&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; echo &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;deb http:&#x2F;&#x2F;dl.google.com&#x2F;linux&#x2F;chrome&#x2F;deb&#x2F; stable main&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; tee &#x2F;etc&#x2F;apt&#x2F;sources.list.d&#x2F;google-chrome.list&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo apt update&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo apt install google-chrome-stable&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Reference: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.google.com&#x2F;linuxrepositories&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.google.com&#x2F;linuxrepositories&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;visual-studio-code&quot;&gt;Visual Studio Code&lt;a class=&quot;zola-anchor&quot; href=&quot;#visual-studio-code&quot; aria-label=&quot;Anchor link for: visual-studio-code&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo wget&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;O&lt;&#x2F;span&gt; - https:&#x2F;&#x2F;tagplus5.github.io&#x2F;vscode-ppa&#x2F;ubuntu&#x2F;gpg.key&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; apt-key add -&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo wget&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;O&lt;&#x2F;span&gt; &#x2F;etc&#x2F;apt&#x2F;sources.list.d&#x2F;vscode.list https:&#x2F;&#x2F;tagplus5.github.io&#x2F;vscode-ppa&#x2F;ubuntu&#x2F;vscode.list&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo apt update&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo apt install code&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Reference: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tagplus5&#x2F;vscode-ppa&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;tagplus5&#x2F;vscode-ppa&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zotero-standalone&quot;&gt;Zotero Standalone&lt;a class=&quot;zola-anchor&quot; href=&quot;#zotero-standalone&quot; aria-label=&quot;Anchor link for: zotero-standalone&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo apt install software-properties-common&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo add-apt-repository ppa:smathot&#x2F;cogscinl&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo apt-get update&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo apt-get install zotero-standalone&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>titlesec (Latex package) doesn&#x27;t create section numbers on version 2.10.1</title>
		<published>2016-11-08T00:00:00+00:00</published>
		<updated>2016-11-08T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/latex-titlesec-does-not-create-section-numbers-on-v2-10-1/" type="text/html"/>
		<id>https://thadaw.com/posts/latex-titlesec-does-not-create-section-numbers-on-v2-10-1/</id>
		<content type="html">&lt;p&gt;I found this bug on yesterday.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-problem&quot; aria-label=&quot;Anchor link for: the-problem&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;When importing &lt;code&gt;titlesec&lt;&#x2F;code&gt; in latex document, the latex compiler (I use &lt;code&gt;xelatex&lt;&#x2F;code&gt;) doesn&#x27;t generate all section numbers.&lt;&#x2F;p&gt;
&lt;p&gt;This bug have been reported on &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;bugs.launchpad.net&#x2F;ubuntu&#x2F;+source&#x2F;texlive-extra&#x2F;+bug&#x2F;1574052&quot;&gt;https:&#x2F;&#x2F;bugs.launchpad.net&#x2F;ubuntu&#x2F;+source&#x2F;texlive-extra&#x2F;+bug&#x2F;1574052&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;The solution&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-solution&quot; aria-label=&quot;Anchor link for: the-solution&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;The solutions are discussed in &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;tex.stackexchange.com&#x2F;questions&#x2F;299969&#x2F;titlesec-loss-of-section-numbering-with-the-new-update-2016-03-15&quot;&gt;http:&#x2F;&#x2F;tex.stackexchange.com&#x2F;questions&#x2F;299969&#x2F;titlesec-loss-of-section-numbering-with-the-new-update-2016-03-15&lt;&#x2F;a&gt;.
You only upgrade the package version from &lt;code&gt;2.10.1&lt;&#x2F;code&gt; to &lt;code&gt;2.10.2&lt;&#x2F;code&gt; manually. The instruction is following below:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Download the package for version &lt;code&gt;2.10.2&lt;&#x2F;code&gt; from &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.ctan.org&#x2F;pkg&#x2F;titlesec?lang=en&quot;&gt;CTAN&lt;&#x2F;a&gt; or you can &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;mirrors.ctan.org&#x2F;macros&#x2F;latex&#x2F;contrib&#x2F;titlesec.zip&quot;&gt;download directly&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Unzip the downloaded file&lt;&#x2F;li&gt;
&lt;li&gt;Copy them into &lt;code&gt;&#x2F;usr&#x2F;share&#x2F;texlive&#x2F;texmf-dist&#x2F;tex&#x2F;latex&#x2F;titlesec&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;What about you? If this solution can help you, please share.
Thank you&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Awesome หนึ่งในคำสำคัญ (Keyword) ที่โปรแกรมเมอร์ทุกคนควรจะรู้จักไว้</title>
		<published>2016-07-03T00:00:00+00:00</published>
		<updated>2016-07-03T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/awesome-is-a-word-of-keywords-that-all-programmers-should-know-th/" type="text/html"/>
		<id>https://thadaw.com/posts/awesome-is-a-word-of-keywords-that-all-programmers-should-know-th/</id>
		<content type="html">&lt;p&gt;สวัสดีครับ วันนี้ผมจะมานำเสนอคำๆ หนึ่งที่โปรแกรมเมอร์ทุกคนควรที่จะรู้จักไว้ ซึ่ง อยากจะบอกว่ามันมีประโยชน์มากๆ ในการเขียนโปรแกรม ผมว่าหลายๆ คนที่กำลังอ่านบทความนี้อาจจะเคยรู้จักหรือ เคยได้ยินมาบ้าง แต่สำหรับคนที่ไม่เคยได้ยินมาก่อน ลองมาทำความรู้จักกับมันดูนะครับ มันมีประโยชน์ต่อชีวิตมากๆ เลย&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;upic.me&#x2F;i&#x2F;6r&#x2F;laptop-1035345_640.jpg&quot; alt=&quot;Laptop&quot; &#x2F;&gt;
&lt;em&gt;Taken by &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pixabay.com&#x2F;en&#x2F;users&#x2F;parthshah000-628805&#x2F;&quot;&gt;parthshah000&lt;&#x2F;a&gt;, CC0 Public Domain License&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าเราลองเปิดพจนานุกรมดู เราจะพบว่า คำๆนี้ฝรั่งใช้ในความหมายของคำแสลง ที่แปลเป็นไทยได้ประมาณว่า&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;เห้ยย เจ๋งว่ะ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;สุดยอดดด&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;โคตรเจ๋ง&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;สุโค่ยยยยยย&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;อะไรประมาณนี้&lt;&#x2F;p&gt;
&lt;h3 id=&quot;aelwthaaainkhwaamhmaaykh-ngopraekrmem-rla-mankhuue-aair&quot;&gt;แล้วถ้าในความหมายของโปรแกรมเมอร์ล่ะ มันคืออะไร?&lt;a class=&quot;zola-anchor&quot; href=&quot;#aelwthaaainkhwaamhmaaykh-ngopraekrmem-rla-mankhuue-aair&quot; aria-label=&quot;Anchor link for: aelwthaaainkhwaamhmaaykh-ngopraekrmem-rla-mankhuue-aair&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;...ถ้าคุณเป็นนักศึกษา Awesome ก็เปรียบเสมือนกับ&lt;strong&gt;คลังของโพยข้อสอบ&lt;&#x2F;strong&gt; ทุกวิชา ทุกคณะของมหาวิทยาลัย ทั้งประเทศ&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;...ถ้าคุณทำงานแล้ว Awesome ก็เปรียบเสมือน&lt;strong&gt;สารบัญของห้องสมุดที่รวบรวมทุกอย่าง&lt;&#x2F;strong&gt; ที่มีประโยชน์เข้าไว้ด้วยกัน และมีการจัดหมวดหมู่ คล้ายๆ กับหนังสือในห้องสมุด&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;แล้วมันคืออะไรล่ะ&lt;&#x2F;p&gt;
&lt;p&gt;คำว่า Awesome ถ้าเราดูตามความหมายจาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome&quot;&gt;แหล่งรวบรวมข้อมูล Awesome ที่ใหญ่ที่สุด&lt;&#x2F;a&gt; ซึ่งถูกจัดเก็บไว้บน GitHub นั้นมี&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome&#x2F;blob&#x2F;master&#x2F;awesome.md&quot;&gt;คำแถลงการณ์ของ Awesome&lt;&#x2F;a&gt; บอกไว้ว่า&lt;&#x2F;p&gt;
&lt;h3 id=&quot;awesome-kkhuue&quot;&gt;Awesome ก็คือ&lt;a class=&quot;zola-anchor&quot; href=&quot;#awesome-kkhuue&quot; aria-label=&quot;Anchor link for: awesome-kkhuue&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;สารบัญของรายการต่างๆที่ โคตรเจ๋ง (awesome) ซึ่งรวบรวมเป็นหมู่หมวดไว้&lt;&#x2F;strong&gt; และสิ่งที่ใส่เข้ามาใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome&quot;&gt;Awesome&lt;&#x2F;a&gt; จะต้อง awesome จริงๆ ถึงจะทำเกิด &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome&quot;&gt;Awesome&lt;&#x2F;a&gt; ได้&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าอ่านแล้วยังนึกภาพไม่ออก ลองเข้าไปดูที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome&quot;&gt;Awesome&lt;&#x2F;a&gt; หรือลองเลือกรายการข้างล่างที่คุณสนใจดู แล้วคุณจะพบกับความ awesome อย่างที่เค้าว่าจริงๆ&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;a class=&quot;zola-anchor&quot; href=&quot;#table-of-contents&quot; aria-label=&quot;Anchor link for: table-of-contents&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#platforms&quot;&gt;Platforms&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#programming-languages&quot;&gt;Programming Languages&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#front-end-development&quot;&gt;Front-End Development&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#back-end-development&quot;&gt;Back-End Development&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#computer-science&quot;&gt;Computer Science&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#big-data&quot;&gt;Big Data&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#theory&quot;&gt;Theory&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#books&quot;&gt;Books&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#editors&quot;&gt;Editors&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#gaming&quot;&gt;Gaming&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#development-environment&quot;&gt;Development Environment&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#entertainment&quot;&gt;Entertainment&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#databases&quot;&gt;Databases&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#media&quot;&gt;Media&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#learn&quot;&gt;Learn&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#security&quot;&gt;Security&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#content-management-system&quot;&gt;Content Management System&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome#miscellaneous&quot;&gt;Miscellaneous&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;นอกจากที่จะมี &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome&quot;&gt;Awesome&lt;&#x2F;a&gt; ที่รวบรวมทุกอย่างไว้แล้ว ผู้คนใน GitHub ต่างสร้างร่วมไม้ร่วมมือกันสร้าง Awesome ในเรื่องที่ตนสนใจ ยกตัวอย่างเช่น ผมสนใจเกี่ยวกับ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.docker.com&#x2F;&quot;&gt;Docker&lt;&#x2F;a&gt; ก็มี Awesome ที่ชื่อว่า &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;veggiemonk&#x2F;awesome-docker&quot;&gt;awesome-docker&lt;&#x2F;a&gt; ที่รวบรวมสิ่งต่างๆ เกี่ยวกับ Docker ที่เหมาะสมสำหรับทั้งมือใหม่ และคนที่ต้องการต่อยอดการใช้งาน Docker&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cchar-aair-yuula-ekhaa-google-aelwphimph-awesome-eruue-ngthiikhunsnaicch-ely&quot;&gt;จะรออะไรอยู่ล่ะ! เข้า google แล้วพิมพ์ awesome + เรื่องที่คุณสนใจ เลย&lt;a class=&quot;zola-anchor&quot; href=&quot;#cchar-aair-yuula-ekhaa-google-aelwphimph-awesome-eruue-ngthiikhunsnaicch-ely&quot; aria-label=&quot;Anchor link for: cchar-aair-yuula-ekhaa-google-aelwphimph-awesome-eruue-ngthiikhunsnaicch-ely&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;ป.ล. แล้วถ้าหาไม่เจอล่ะ ชุมชน GitHub กำลังรอให้คุณสร้างอยู่ครับ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;hruue-thaanuekaim-k-kaipthii-awesome-k-nely&quot;&gt;หรือถ้านึกไม่ออก ก็ไปที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sindresorhus&#x2F;awesome&quot;&gt;Awesome&lt;&#x2F;a&gt; ก่อนเลย&lt;a class=&quot;zola-anchor&quot; href=&quot;#hruue-thaanuekaim-k-kaipthii-awesome-k-nely&quot; aria-label=&quot;Anchor link for: hruue-thaanuekaim-k-kaipthii-awesome-k-nely&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธีการเริ่มการทำงาน VM ของ VirtualBox แบบทำงานเบื้องหลัง</title>
		<published>2016-06-27T00:00:00+00:00</published>
		<updated>2016-06-27T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/starting-vitualbox-vm-with-headless-mode-th/" type="text/html"/>
		<id>https://thadaw.com/posts/starting-vitualbox-vm-with-headless-mode-th/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;สำหรับความสามารถนี้รองรับเฉพาะ &lt;strong&gt;VirtualBox รุ่น 5.0&lt;&#x2F;strong&gt; เป็นต้นไปนะครับ สามารถดูรายละเอียดเพิ่มเติมได้ที่&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;blogs.oracle.com&#x2F;virtualization&#x2F;entry&#x2F;oracle_vm_virtualbox_5_07&quot;&gt;บล็อกของ oracle&lt;&#x2F;a&gt; เลยครับ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;สวัสดีครับ วันนี้ผมจะนำเสนอวิธีการเริ่มการทำงาน virtual machine (VM) โดยไม่มี GUI ขึ้นมากินทรัพยากรของคอมเตอร์เครื่องเรา (Host Machine) โดยวิธีการเหมาะสำหรับการใช้งานแบบ remote เท่านั้น หรือก็คือ คุณจะต้องใช้ ssh เพื่อเชื่อมเข้าไปใช้งาน VM&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;สำหรับคนที่ใช้ windows โปรแกรมที่แนะนำสำหรับการใช้ ssh คือ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.putty.org&#x2F;&quot;&gt;Putty&lt;&#x2F;a&gt; ครับ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;withiikaaraichngaandwy-gui&quot;&gt;วิธีการใช้งานด้วย GUI&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiikaaraichngaandwy-gui&quot; aria-label=&quot;Anchor link for: withiikaaraichngaandwy-gui&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;starting-vitualbox-vm-with-headless-mode-th&#x2F;2016-06-27-starting-vitualbox-vm-with-headless-mode.jpg&quot; alt=&quot;GUI mode for starting virtualbox vm in headless mode&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;withiikaaraichphaan-command-line-cli&quot;&gt;วิธีการใช้ผ่าน Command Line (CLI)&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiikaaraichphaan-command-line-cli&quot; aria-label=&quot;Anchor link for: withiikaaraichphaan-command-line-cli&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;สำหรับคนที่ใช้ Windows ให้ใช้ path เต็มๆ ของ Virtualbox แทน หรือตั้งค่า variable environment ก็ได้ เช่น &lt;code&gt;&quot;C:\Program Files\Oracle\VirtualBox\VBoxManage&quot;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;แสดงรายชื่อของ Virtual machine ที่มีอยู่ในเครื่อง&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; VBoxManage list vms&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Sandbox&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;754f8cac-1fff-4863-952e-ba81ebf9efc7&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-end z-shell&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;md9-dev&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;dd6cfb08-0914-4b6f-b78a-7aa301fc8813&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-end z-shell&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;default&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;fb0f8838-0f24-44d3-bd6f-8855ff2e4262&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-end z-shell&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เริ่มต้นการทำงาน Virtual machine แบบทำงานเบื้องหลัง (headless mode)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; VBoxManage startvm default&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;type&lt;&#x2F;span&gt; headless&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ปิดการทำงาน Virtual machine&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; VBoxManage controlvm default poweroff&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;aanephimetim&quot;&gt;อ่านเพิ่มเติม&lt;a class=&quot;zola-anchor&quot; href=&quot;#aanephimetim&quot; aria-label=&quot;Anchor link for: aanephimetim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;schier.co&#x2F;blog&#x2F;2013&#x2F;03&#x2F;13&#x2F;start-virtualbox-vm-in-headless-mode.html&quot;&gt;&quot;Start VirtualBox VM in Headless Mode&quot; by Gregory Schier&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.virtualbox.org&#x2F;manual&#x2F;ch07.html#vboxheadless&quot;&gt;Vbox headless - Official VirtualBox Doc&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.virtualbox.org&#x2F;manual&#x2F;ch08.html#vboxmanage-startvm&quot;&gt;vboxmanage startvm - Official VirtualBox Doc&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;windows-toolbox&#x2F;blob&#x2F;a1962e0e26d33f19d8c6f582c42b0c423d9bc644&#x2F;vbox.bat&quot;&gt;ตัวอย่างการนำคำสั่งการเริ่มต้น vm ของ virtualbox ไปใช้งาน&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>เปิด Hotspot WiFi เองโดยที่ต้องไม่พึ่งโปรแกรมใดๆ บน Windows</title>
		<published>2016-06-04T00:00:00+00:00</published>
		<updated>2016-06-04T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/script-for-creating-a-wifi-hotspot-without-install-wifi-hotspot-tools-th/" type="text/html"/>
		<id>https://thadaw.com/posts/script-for-creating-a-wifi-hotspot-without-install-wifi-hotspot-tools-th/</id>
		<content type="html">&lt;p&gt;โปรแกรมทางเลือกสำหรับการสร้าง WiFi Hotspot ใช้งานเองโดยไม่ต้องพึงโปรแกรมอื่นๆ จากคอมพิวเตอร์ของคุณ เช่น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.connectify.me&#x2F;&quot;&gt;Connectify&lt;&#x2F;a&gt; หรือ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.mhotspot.com&#x2F;&quot;&gt;mHotspot&lt;&#x2F;a&gt; เป็นต้น&lt;&#x2F;p&gt;
&lt;p&gt;โดยทำการทดสอบบน Windows 7,8, 10 แล้วใช้งานได้&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tangkhaaebuue-ngtnk-naichngaan&quot;&gt;ตั้งค่าเบื้องต้นก่อนใช้งาน&lt;a class=&quot;zola-anchor&quot; href=&quot;#tangkhaaebuue-ngtnk-naichngaan&quot; aria-label=&quot;Anchor link for: tangkhaaebuue-ngtnk-naichngaan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;คัดลอกโค๊ดข้างล่าง หรือ ดาวโหลดที่ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;mildronize&#x2F;8d159d35497c56368914&quot;&gt;Gist Github ของผม&lt;&#x2F;a&gt; ไปใส่ในไฟล์ ชื่อ &lt;code&gt;hotspot.bat&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ตรวจสอบดูว่า มี Network Adapter ที่มีชนิดเป็น &lt;em&gt;Microsoft Virtual WiFi Miniport Adapter&lt;&#x2F;em&gt; ใน &lt;em&gt;Network and Sharing Center &amp;gt; Change Adapter Setting&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;ถ้าไม่มีให้รัน &lt;code&gt;hotspot.bat&lt;&#x2F;code&gt; หนึ่งครั้ง มันจะสร้าง Adapter ตัวนั้นออกมา และปิดโปรแกรมไปก่อน แล้วก็เปลี่ยนชื่อเป็น &lt;code&gt;Hotspot&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ถ้ามีก็ให้เปลี่ยนชื่อเป็น &lt;code&gt;Hotspot&lt;&#x2F;code&gt; เช่นกัน&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;ไม่เปลี่ยนชื่อเป็น Hotspot แต่ต้องไปแก้ในโค๊ด ตรงบรรทัดที่ &lt;code&gt;set wirelessName=Hotspot&lt;&#x2F;code&gt; ให้แก้เป็นชื่อของ adapter ที่มีชนิดเป็น &lt;em&gt;Microsoft Virtual WiFi Miniport Adapter&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;สั่งแชร์อินเตอร์เน็ตจากสายแลน (Ethernet) ไปยัง Hotspot โดย&lt;&#x2F;li&gt;
&lt;li&gt;คลิกขวา Ethernet Adapter ใน &lt;em&gt;Network and Sharing Center &amp;gt; Change Adapter Setting&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;เลือก Properties และไปกดที่แท็บ Sharing&lt;&#x2F;li&gt;
&lt;li&gt;ติ๊กถูกที่ &lt;strong&gt;Allow other network users to connect through this computer’s Internet connection&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;จากนั้นเลือกชื่อของ Hotspot ที่เราตั้งไว้จากข้อ 2 ในที่นี่คือ &lt;code&gt;Hotspot&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;เริ่มทำงานโดยรัน &lt;code&gt;hotspot.bat&lt;&#x2F;code&gt; หรือ &lt;code&gt;hotspot&lt;&#x2F;code&gt; หรือผ่าน command line&lt;&#x2F;li&gt;
&lt;li&gt;ตั้งค่าชื่อ Hotspot ( &lt;em&gt;What is Adhoc name ?&lt;&#x2F;em&gt; )&lt;&#x2F;li&gt;
&lt;li&gt;ใส่รหัสผ่าน ( &lt;em&gt;Password ?&lt;&#x2F;em&gt; )&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;cli&quot;&gt;CLI&lt;a class=&quot;zola-anchor&quot; href=&quot;#cli&quot; aria-label=&quot;Anchor link for: cli&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;hospot &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; ตั้งค่า ชื่อ Wifi และรหัสผ่าน ใหม่&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;hospot&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; start &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; เปิด Hotspot&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;hospot&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; stop &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; ปิด Hotspot&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;hospot&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; restart &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; ปิดแล้วเปิดใหม่อีกครั้ง&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;okhdkaaropraekrmepid-hotspot-bn-windows&quot;&gt;โค๊ดการโปรแกรมเปิด Hotspot บน Windows&lt;a class=&quot;zola-anchor&quot; href=&quot;#okhdkaaropraekrmepid-hotspot-bn-windows&quot; aria-label=&quot;Anchor link for: okhdkaaropraekrmepid-hotspot-bn-windows&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;mildronize&#x2F;8d159d35497c56368914&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;mildronize&#x2F;8d159d35497c56368914&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bat&quot; class=&quot;language-bat z-code&quot;&gt;&lt;code class=&quot;language-bat&quot; data-lang=&quot;bat&quot;&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-at z-dosbatch&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;ECHO&lt;&#x2F;span&gt; OFF
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;echo&lt;&#x2F;span&gt; Hotspot
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;echo&lt;&#x2F;span&gt; .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;set&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-dosbatch&quot;&gt;wirelessName&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-dosbatch&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-dosbatch&quot;&gt;Hotspot&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-dosbatch&quot;&gt;IF&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-dosbatch&quot;&gt;==&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;start&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-statement z-dosbatch&quot;&gt;goto&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-dosbatch&quot;&gt;&lt;span class=&quot;z-variable z-function z-dosbatch&quot;&gt;START&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-dosbatch&quot;&gt;IF&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-dosbatch&quot;&gt;==&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;stop&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-statement z-dosbatch&quot;&gt;goto&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-dosbatch&quot;&gt;&lt;span class=&quot;z-variable z-function z-dosbatch&quot;&gt;STOP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-dosbatch&quot;&gt;IF&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-dosbatch&quot;&gt;==&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;restart&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-statement z-dosbatch&quot;&gt;goto&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-dosbatch&quot;&gt;&lt;span class=&quot;z-variable z-function z-dosbatch&quot;&gt;RESTART&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-dosbatch&quot;&gt;IF&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-dosbatch&quot;&gt;==&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;stat&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-statement z-dosbatch&quot;&gt;goto&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-dosbatch&quot;&gt;&lt;span class=&quot;z-variable z-function z-dosbatch&quot;&gt;STAT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;set&lt;&#x2F;span&gt; &#x2F;p &lt;span class=&quot;z-meta z-prompt z-set z-dosbatch&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-dosbatch&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-dosbatch&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-dosbatch&quot;&gt;What is Adhoc name ? (Press S to stop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;):
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-dosbatch&quot;&gt;IF&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-begin z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;name&lt;span class=&quot;z-punctuation z-definition z-variable z-end z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-dosbatch&quot;&gt;==&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;S&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-statement z-dosbatch&quot;&gt;goto&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-dosbatch&quot;&gt;&lt;span class=&quot;z-variable z-function z-dosbatch&quot;&gt;STOP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-dosbatch&quot;&gt;IF&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-begin z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;name&lt;span class=&quot;z-punctuation z-definition z-variable z-end z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-dosbatch&quot;&gt;==&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-statement z-dosbatch&quot;&gt;goto&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-dosbatch&quot;&gt;&lt;span class=&quot;z-variable z-function z-dosbatch&quot;&gt;START&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-dosbatch&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-label z-dosbatch&quot;&gt;SET&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;echo&lt;&#x2F;span&gt; Start adhoc!
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;set&lt;&#x2F;span&gt; &#x2F;p &lt;span class=&quot;z-meta z-prompt z-set z-dosbatch&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-dosbatch&quot;&gt;pass&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-dosbatch&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-dosbatch&quot;&gt;Password ? :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;netsh&lt;&#x2F;span&gt; wlan &lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;set&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-dosbatch&quot;&gt;hostednetwork mode&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-dosbatch&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-dosbatch&quot;&gt;allow ssid=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-begin z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;name&lt;span class=&quot;z-punctuation z-definition z-variable z-end z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-dosbatch&quot;&gt; key=&lt;span class=&quot;z-variable z-other z-readwrite z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-begin z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;pass&lt;span class=&quot;z-punctuation z-definition z-variable z-end z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;netsh&lt;&#x2F;span&gt; wlan &lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;start&lt;&#x2F;span&gt; hostednetwork
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;netsh&lt;&#x2F;span&gt; interface ip &lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;set&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-dosbatch&quot;&gt;address name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-dosbatch&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-begin z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;wirelessName&lt;span class=&quot;z-punctuation z-definition z-variable z-end z-dosbatch&quot;&gt;%&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dosbatch&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-dosbatch&quot;&gt; source=dhcp&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-control z-statement z-dosbatch&quot;&gt;goto&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-dosbatch&quot;&gt;&lt;span class=&quot;z-variable z-function z-dosbatch&quot;&gt;EXIT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-dosbatch&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-label z-dosbatch&quot;&gt;START&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;echo&lt;&#x2F;span&gt; Starting hotspot!
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;netsh&lt;&#x2F;span&gt; wlan &lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;start&lt;&#x2F;span&gt; hostednetwork
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-control z-statement z-dosbatch&quot;&gt;goto&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-dosbatch&quot;&gt;&lt;span class=&quot;z-variable z-function z-dosbatch&quot;&gt;EXIT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-dosbatch&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-label z-dosbatch&quot;&gt;STOP&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;echo&lt;&#x2F;span&gt; Stopping hotspot!
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;netsh&lt;&#x2F;span&gt; wlan stop hostednetwork
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-control z-statement z-dosbatch&quot;&gt;goto&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-dosbatch&quot;&gt;&lt;span class=&quot;z-variable z-function z-dosbatch&quot;&gt;EXIT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-dosbatch&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-label z-dosbatch&quot;&gt;RESTART&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;echo&lt;&#x2F;span&gt; Restarting hotspot!
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;netsh&lt;&#x2F;span&gt; wlan stop hostednetwork
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;netsh&lt;&#x2F;span&gt; wlan &lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;start&lt;&#x2F;span&gt; hostednetwork
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-control z-statement z-dosbatch&quot;&gt;goto&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-dosbatch&quot;&gt;&lt;span class=&quot;z-variable z-function z-dosbatch&quot;&gt;EXIT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-dosbatch&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-label z-dosbatch&quot;&gt;STAT&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;netsh&lt;&#x2F;span&gt; wlan show hostednetwork
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-control z-statement z-dosbatch&quot;&gt;goto&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-dosbatch&quot;&gt;&lt;span class=&quot;z-variable z-function z-dosbatch&quot;&gt;EXIT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-dosbatch&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-label z-dosbatch&quot;&gt;EXIT&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dosbatch&quot;&gt;&lt;span class=&quot;z-keyword z-command z-dosbatch&quot;&gt;pause&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธีติดตั้งเกม Hearthstone: Heroes of Warcraft บน Debian</title>
		<published>2016-03-18T00:00:00+00:00</published>
		<updated>2016-03-18T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/how-to-install-hearthstone-heroes-of-warcraft-on-debian-th/" type="text/html"/>
		<id>https://thadaw.com/posts/how-to-install-hearthstone-heroes-of-warcraft-on-debian-th/</id>
		<content type="html">&lt;p&gt;ผมได้โอกาสลองเล่น Hearthstone: Heroes of Warcraft ดู ปรากฏว่าสนุกมากๆ เลยครับ ทำออกมาดีเลยที่เดียว แถมมีทุก platform เลย ยกเว้น Linux แอบน้อยใจนิดๆ เลยได้ลองหาวิธีติดตั้งดู ซึ่งก็ไม่ได้ยากอย่างที่คิด ถ้าใครเป็นมือใหม่ลองทำตามขั้นตอนนี้เลยนะครับ&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: ผมทดสอบบน Debian sid สถาปัตยกรรมแบบ amd64 นะครับ ดังนั้นปัญหาอาจจะไม่เหมือนซะทีเดียว แต่ก็พอนำมาอ้างอิงได้ครับ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;khant-n&quot;&gt;ขั้นตอน&lt;a class=&quot;zola-anchor&quot; href=&quot;#khant-n&quot; aria-label=&quot;Anchor link for: khant-n&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;ทำเพิ่มสถาปัตยกรรมของคลังเก็บโค๊ด (repository) สำหรับการติดตั้งแพคเก็ต 32 bit หรือ i386 แล้วสั่งอัพเดทรายการของคลังเก็บโค๊ด (repository) เนื่องจากการติดตั้ง Hearthstone จำเป็นใช้โค๊ดบางอย่างแบบ i386 ดังนี้&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;อ่านก่อน: ถ้าใครที่ใช้ Debian 32 bit (i386) อยู่แล้วให้ข้ามขั้นตอนนี้ไปได้เลยครับ ขั้นตอนนี้สำหรับ Debian 64 bit(amd64) นะครับ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# dpkg --add-architecture i386
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# aptitude update
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;อันดับแรก ติดตั้ง &lt;code&gt;wine&lt;&#x2F;code&gt; ซึ่งเป็นโปรแกรมบน Linux สำหรับทำให้โปรแกรมบน Windows สามารถทำงานบน Linux ได้ครับ&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# aptitude install wine
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ทำการสำรองข้อมูลของ &lt;code&gt;wine&lt;&#x2F;code&gt; ก่อน ถ้ามี&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ mv ~&#x2F;.wine ~&#x2F;.wine-old
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;สร้างสภาพแวดล้อมแบบ 32 bit หรือ i386 โดย&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ env WINEARCH=win32 WINEPREFIX=$HOME&#x2F;.wine wineboot -u
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;กำหนดไลบรารี่ที่จำเป็นเพิ่มเติม โดยมี &lt;code&gt;dbghelp&lt;&#x2F;code&gt; และ &lt;code&gt;msvcp100&lt;&#x2F;code&gt; โดยการ&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;สั่งให้คำสั่ง &lt;code&gt;winecfg&lt;&#x2F;code&gt; เพื่อทำการตั้งค่า&lt;&#x2F;li&gt;
&lt;li&gt;ในแท็บของไลบรารี่ (Libraries) นั้นให้กด สร้าง &lt;code&gt;dbghelp&lt;&#x2F;code&gt; แล้วทำการแก้ไขเป็น &lt;code&gt;disabled&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ในแท็บของไลบรารี่ (Libraries) นั้นให้กด สร้าง &lt;code&gt;msvcp100&lt;&#x2F;code&gt; แล้วทำการแก้ไขเป็น &lt;code&gt;native, then builtin&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;สุดท้ายต้องมั่นใจว่า&lt;&#x2F;strong&gt; ตั้งค่าสภาพแวดล้อมเป็น &lt;code&gt;Windows XP&lt;&#x2F;code&gt; แล้ว ไม่อย่างนั้น จะเจออาการจอขาวเวลาเข้าเกม&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ดาวโหลดจากหน้าเว็บได้&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;eu.battle.net&#x2F;hearthstone&#x2F;en&#x2F;&quot;&gt;ที่นี่&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;จากนั้นให้กดติดตั้งเกม hearthstone&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;สุดท้ายขอให้สนุกกับการเล่นเกม Hearthstone นะครับ&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;aehlngkh-muulephimetim-aela-aang-ing&quot;&gt;แหล่งข้อมูลเพิ่มเติม และอ้างอิง&lt;a class=&quot;zola-anchor&quot; href=&quot;#aehlngkh-muulephimetim-aela-aang-ing&quot; aria-label=&quot;Anchor link for: aehlngkh-muulephimetim-aela-aang-ing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=WZyEu2OrgzU&quot;&gt;ขั้นตอนการติดตั้งแบบวิดิโอผ่าน Youtube เป็นภาษาอังกฤษ&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;appdb.winehq.org&#x2F;objectManager.php?sClass=version&amp;amp;iId=30038&quot;&gt;ผลการทดสอบของผู้เล่นคนอื่นๆ โดยติดตั้ง Hearthstone ผ่าน wine รวมถึงวิธีการแก้ปัญหา เวลาเจอบัคต่างๆ&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ใช้งานภาษาไทยบน XeLaTeX ฉบับรีบร้อน</title>
		<published>2016-03-05T00:00:00+00:00</published>
		<updated>2016-03-05T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/quickly-use-thai-for-xelatex-th/" type="text/html"/>
		<id>https://thadaw.com/posts/quickly-use-thai-for-xelatex-th/</id>
		<content type="html">&lt;p&gt;เนื่องจากผมได้สืบค้นการพิมพ์ไทย ปรากฎว่าหลายๆ แหล่งข้อมูลยังใช้งานยากอยู่ จึงนำมาประยุกต์ เพื่อให้สามารถพิมพ์ได้โดยเร็ว โดยที่ไม่ต้องกระทบส่วนอื่นๆ ของไฟล์ &lt;code&gt;.tex&lt;&#x2F;code&gt; ครับ&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;อ่านก่อน: วิธีการนี้เหมาะสำหรับต้องการพิมพ์ภาษาไทยเป็นภาษารอง จากภาษาอังกฤษ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;taw-yaangaifl-tex&quot;&gt;ตัวอย่างไฟล์ .tex&lt;a class=&quot;zola-anchor&quot; href=&quot;#taw-yaangaifl-tex&quot; aria-label=&quot;Anchor link for: taw-yaangaifl-tex&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;latex&quot; class=&quot;language-latex z-code&quot;&gt;&lt;code class=&quot;language-latex&quot; data-lang=&quot;latex&quot;&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-preamble z-documentclass z-latex&quot;&gt;&lt;span class=&quot;z-keyword z-control z-preamble z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;documentclass&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-bracket z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-bracket z-begin z-latex&quot;&gt;[&lt;&#x2F;span&gt;a4paper&lt;span class=&quot;z-punctuation z-definition z-group z-bracket z-end z-latex&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-documentclass z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-documentclass z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-support z-class z-latex&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class z-latex&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class z-latex&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class z-latex&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class z-latex&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class z-latex&quot;&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class z-latex&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-keyword z-control z-preamble z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;usepackage&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-support z-class z-latex&quot;&gt;fontspec&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-keyword z-control z-preamble z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;usepackage&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-support z-class z-latex&quot;&gt;xunicode&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-keyword z-control z-preamble z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;usepackage&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-support z-class z-latex&quot;&gt;xltxtra&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-general z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;XeTeXlinebreaklocale&lt;&#x2F;span&gt; “th_TH” &lt;span class=&quot;z-comment z-line z-percentage z-tex&quot;&gt;% สำหรับตัดคำภาษาไทย
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-general z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;newenvironment&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;thai&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;    &lt;span class=&quot;z-meta z-function z-newcommand z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-newcommand z-latex&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-newcommand z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;renewcommand&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-latex&quot;&gt;&lt;span class=&quot;z-entity z-name z-newcommand z-latex&quot;&gt;\baselinestretch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;1.2&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;    &lt;span class=&quot;z-support z-function z-general z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;fontspec&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;TH Sarabun New&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;[Scale=1.23]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-general z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;par&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-begin z-latex&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-begin z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;begin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-latex&quot;&gt;document&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-general z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;noindent&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-begin z-latex&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-begin z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;begin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-latex&quot;&gt;thai&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;  ป้ากะปู่ กู้อีจู้ มันคืออะไรที่วรรคยุคเยอะแยะเต็มไปหมดเลย ป้ากะปู่ กู้อีจู้ มันคืออะไรที่วรรคยุคเยอะแยะเต็มไปหมดเลย ป้ากะปู่ กู้อีจู้ มันคืออะไรที่วรรคยุคเยอะแยะเต็มไปหมดเลย ป้ากะปู่ กู้อีจู้ มันคืออะไรที่วรรคยุคเยอะแยะเต็มไปหมดเลย&lt;span class=&quot;z-constant z-character z-newline z-latex&quot;&gt;\\&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-end z-latex&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-end z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-latex&quot;&gt;thai&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-general z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;noindent&lt;&#x2F;span&gt; The quick brown fox jumps over the lazy dog&lt;span class=&quot;z-constant z-character z-newline z-latex&quot;&gt;\\&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-function z-textbf z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-textbf z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;textbf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-textbf z-latex&quot;&gt;&lt;span class=&quot;z-markup z-bold z-textbf z-latex&quot;&gt;The quick brown fox jumps over the lazy dog&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-newline z-latex&quot;&gt;\\&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-function z-textit z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-textit z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;textit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-textit z-latex&quot;&gt;&lt;span class=&quot;z-markup z-italic z-textit z-latex&quot;&gt;The quick brown fox jumps over the lazy dog&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-newline z-latex&quot;&gt;\\&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-function z-textsl z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-textsl z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;textsl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-textsl z-latex&quot;&gt;&lt;span class=&quot;z-markup z-italic z-textsl z-latex&quot;&gt;The quick brown fox jumps over the lazy dog&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-newline z-latex&quot;&gt;\\&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-function z-textbf z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-textbf z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;textbf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-textbf z-latex&quot;&gt;&lt;span class=&quot;z-markup z-bold z-textbf z-latex&quot;&gt;&lt;span class=&quot;z-meta z-function z-textit z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-textit z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;textit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-textit z-latex&quot;&gt;&lt;span class=&quot;z-markup z-italic z-textit z-latex&quot;&gt;The quick brown fox jumps over the lazy dog&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-newline z-latex&quot;&gt;\\&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-function z-texttt z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-texttt z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;texttt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-texttt z-latex&quot;&gt;&lt;span class=&quot;z-markup z-raw z-texttt z-latex&quot;&gt;The quick brown fox jumps over the lazy dog&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-newline z-latex&quot;&gt;\\&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-end z-latex&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-end z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-latex&quot;&gt;document&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;คำเตือน: ในตัวอย่างไฟล์ .tex ข้างบนถูกทดสอบบน XeLatex จาก MikTek บน Windows ถ้าทำงานบนระบบอื่นๆ อาจจะมีปัญหาได้&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;เมื่อแปลงโดยใช้ &lt;code&gt;XeLaTeX&lt;&#x2F;code&gt; จะได้ผลลัพธ์แบบนี้&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;quickly-use-thai-for-xelatex-th&#x2F;2016-03-05-quickly-use-thai-for-xelatex-th.png&quot; alt=&quot;result of xelatex in PDF&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;withiitangkhaaaihsaamaarthphimphphaasaaaithyaid&quot;&gt;วิธีตั้งค่าให้สามารถพิมพ์ภาษาไทยได้&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiitangkhaaaihsaamaarthphimphphaasaaaithyaid&quot; aria-label=&quot;Anchor link for: withiitangkhaaaihsaamaarthphimphphaasaaaithyaid&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เราจะใช้ฟอนต์ &lt;code&gt;TH Sarabun New&lt;&#x2F;code&gt; สำหรับเป็นตัวอย่าง และต้องติดตั้งฟอนต์ไว้ในเครื่องแล้ว&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;แทรก packages ที่จำเป็น รวมถึงการตั้งค่าการตัดคำภาษาไทย&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;latex&quot; class=&quot;language-latex z-code&quot;&gt;&lt;code class=&quot;language-latex&quot; data-lang=&quot;latex&quot;&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-keyword z-control z-preamble z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;usepackage&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-support z-class z-latex&quot;&gt;fontspec&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-keyword z-control z-preamble z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;usepackage&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-support z-class z-latex&quot;&gt;xunicode&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-keyword z-control z-preamble z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;usepackage&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preamble z-usepackage z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-support z-class z-latex&quot;&gt;xltxtra&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-general z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;XeTeXlinebreaklocale&lt;&#x2F;span&gt; “th_TH” &lt;span class=&quot;z-comment z-line z-percentage z-tex&quot;&gt;% สำหรับตัดคำภาษาไทย
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;กำหนดสภาพแวดล้อมใหม่(&lt;code&gt;\newenvironment&lt;&#x2F;code&gt;) สำหรับพิมพ์ภาษาไทยดังนี้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;latex&quot; class=&quot;language-latex z-code&quot;&gt;&lt;code class=&quot;language-latex&quot; data-lang=&quot;latex&quot;&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-general z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;newenvironment&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;thai&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;    &lt;span class=&quot;z-meta z-function z-newcommand z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-newcommand z-latex&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-newcommand z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;renewcommand&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-latex&quot;&gt;&lt;span class=&quot;z-entity z-name z-newcommand z-latex&quot;&gt;\baselinestretch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;1.2&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;    &lt;span class=&quot;z-comment z-line z-percentage z-tex&quot;&gt;% กำหนดขนาดบรรทัด เป็น 1.2
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;    &lt;span class=&quot;z-support z-function z-general z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;fontspec&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;TH Sarabun New&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;[Scale=1.23]   &lt;span class=&quot;z-comment z-line z-percentage z-tex&quot;&gt;% ขยายตัวอกษร เป็น 1.23 เท่า
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-meta z-group z-brace z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-general z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;par&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;kaaraichngaan&quot;&gt;การใช้งาน&lt;a class=&quot;zola-anchor&quot; href=&quot;#kaaraichngaan&quot; aria-label=&quot;Anchor link for: kaaraichngaan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;latex&quot; class=&quot;language-latex z-code&quot;&gt;&lt;code class=&quot;language-latex&quot; data-lang=&quot;latex&quot;&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-begin z-latex&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-begin z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;begin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-latex&quot;&gt;thai&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;ใส่ข้อความภาษาไทยในนี้
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-tex z-latex&quot;&gt;&lt;span class=&quot;z-support z-function z-end z-latex&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-end z-latex&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-backslash z-latex&quot;&gt;\&lt;&#x2F;span&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-begin z-latex&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-latex&quot;&gt;thai&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-brace z-end z-latex&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;a class=&quot;zola-anchor&quot; href=&quot;#useful-resources&quot; aria-label=&quot;Anchor link for: useful-resources&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;thailatex.wordpress.com&#x2F;miktex-27-xetex-with-thai&#x2F;&quot;&gt;การใช้งานภาษาไทยโดยใช้ XeLaTeX&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.ie.eng.chula.ac.th&#x2F;~pramual&#x2F;books&#x2F;XeTeX&#x2F;&quot;&gt;คู่มือการใช้งาน XeLaTeX ฉบับภาษาไทย โดย ดร.ประมวล สุธีจารุวัฒน &lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.sharelatex.com&#x2F;learn&#x2F;Environments&quot;&gt;Tutorial for declaring a new enviroment by sharelatex&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ทำไม mount volume ของ Docker บน Windows แล้วมองไม่เห็นไฟล์</title>
		<published>2016-02-27T00:00:00+00:00</published>
		<updated>2016-02-27T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/why-does-not-see-folder-files-of-mounted-volume-on-docker-from-windows-host-th/" type="text/html"/>
		<id>https://thadaw.com/posts/why-does-not-see-folder-files-of-mounted-volume-on-docker-from-windows-host-th/</id>
		<content type="html">&lt;h2 id=&quot;ekrinnam-saknid&quot;&gt;เกริ่นนำ สักนิด...&lt;a class=&quot;zola-anchor&quot; href=&quot;#ekrinnam-saknid&quot; aria-label=&quot;Anchor link for: ekrinnam-saknid&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ก่อนอ่านบทความนี้น่าจะมีความรู้พื้นฐานเรื่อง &lt;code&gt;Docker&lt;&#x2F;code&gt; และ &lt;code&gt;Docker Machine&lt;&#x2F;code&gt; มาก่อน&lt;&#x2F;p&gt;
&lt;p&gt;สืบเนื่องจาก Docker ที่รันอยู่บน Windows นั้นทำงานอยู่ใน Linux VM ไม่ได้ทำงานบน Windows ตรงๆ&lt;&#x2F;p&gt;
&lt;p&gt;จึงการ mount folder (หรือ ในฝั่งของ Docker เค้าเรียกว่า Volume) นั้น
Mount ได้อย่างมีข้อจำกัด&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: สามารถอ่านแนวคิดของ Docker เพิ่มเติมได้ที่เว็บของ Docker เองในหัวข้อ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.docker.com&#x2F;engine&#x2F;installation&#x2F;windows&#x2F;#learn-the-key-concepts-before-installing&quot;&gt;&quot;Learn the key concepts before installing&quot;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;t-b&quot;&gt;ตอบ&lt;a class=&quot;zola-anchor&quot; href=&quot;#t-b&quot; aria-label=&quot;Anchor link for: t-b&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เกิดจาก VM ที่รัน docker อยู่นั้น ทำการ shared folder ไว้แค่ path ของ &lt;code&gt;C:\Users&lt;&#x2F;code&gt; เท่านั้น&lt;&#x2F;p&gt;
&lt;p&gt;ทำให้ ไม่สามารถ mount path อื่นๆ ได้ เช่น &lt;code&gt;docker run -v &quot;other&#x2F;path:&quot;docker&#x2F;container&#x2F;path&quot;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;โดยค่าเริ่มต้น VM ที่รัน Docker อยู่นั้น ทำกาารการ share folder ไว้ดังนี้
กำหนดให้&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Folder Path: C:\Users
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Folder Name: c&#x2F;Users
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ดังรูป
&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;why-does-not-see-folder-files-of-mounted-volume-on-docker-from-windows-host-th&#x2F;2016-02-27-why-does-not-see-folder-files-of-mounted-volume-on-docker-from-windows-host.png&quot; alt=&quot;this figure show default of mounting path of docker vm on windows&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;สรุปคำสั่ง Docker โดยทำการ mount volume&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;docker run --rm -it -v &amp;quot;&#x2F;&#x2F;[Folder Name]&#x2F;your&#x2F;folder:&#x2F;docker&#x2F;container&#x2F;path&amp;quot; IMAGE_NAME
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;aelweraasaamaarth-mount-aipyang-path-uuen-aidmay&quot;&gt;แล้วเราสามารถ Mount ไปยัง path อื่นๆ ได้มั้ย&lt;a class=&quot;zola-anchor&quot; href=&quot;#aelweraasaamaarth-mount-aipyang-path-uuen-aidmay&quot; aria-label=&quot;Anchor link for: aelweraasaamaarth-mount-aipyang-path-uuen-aidmay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;คิดว่า น่าจะได้ครับ ยังไม่เคยลอง ลองอ่านบทความเพิ่มเติมดู&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;30864466&#x2F;whats-the-best-way-to-share-files-from-windows-to-boot2docker-vm&quot;&gt;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;30864466&#x2F;whats-the-best-way-to-share-files-from-windows-to-boot2docker-vm&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.incrediblemolk.com&#x2F;sharing-a-windows-folder-with-the-boot2docker-vm&quot;&gt;http:&#x2F;&#x2F;www.incrediblemolk.com&#x2F;sharing-a-windows-folder-with-the-boot2docker-vm&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;aanephimetim&quot;&gt;อ่านเพิ่มเติม&lt;a class=&quot;zola-anchor&quot; href=&quot;#aanephimetim&quot; aria-label=&quot;Anchor link for: aanephimetim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Issue on Github: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;docker&#x2F;docker&#x2F;issues&#x2F;18419&quot;&gt;&quot;unable to see folder files in volume mounted from windows host&quot;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Guideline for Upgrading Jekyll from 2.x to 3.x</title>
		<published>2016-02-06T00:00:00+00:00</published>
		<updated>2016-02-06T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/guideline-for-upgrading-jekyll-from-2-x-to-3-x/" type="text/html"/>
		<id>https://thadaw.com/posts/guideline-for-upgrading-jekyll-from-2-x-to-3-x/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;Note: &lt;strong&gt;This guideline is not suitable for default engine of GitHub (Jekyll)&lt;&#x2F;strong&gt;. Because it doesn&#x27;t allow to install any plugin. On the other hand, we can&#x27;t use Jekyll 2 plugin. It must uses in Jekyll 3 way.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;If you are a Jekyll user. You may be heard some news about announcement Jekyll 3.
Then, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;blog&#x2F;2100-github-pages-now-faster-and-simpler-with-jekyll-3-0&quot;&gt;GitHub announced to use the Jekyll 3&lt;&#x2F;a&gt;.
So, there are many changes for Jekyll 3.
It describes in the &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;jekyllrb.com&#x2F;docs&#x2F;upgrading&#x2F;2-to-3&#x2F;&quot;&gt;Jekyll Official page&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;notices&quot;&gt;Notices&lt;a class=&quot;zola-anchor&quot; href=&quot;#notices&quot; aria-label=&quot;Anchor link for: notices&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;This article doesn&#x27;t directly use to upgrade your Jekyll site, but it has some useful guidelines for upgrading by yourself.&lt;&#x2F;li&gt;
&lt;li&gt;This article is following my site upgrading. You can see all changes in my commits (&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;c6adf73f931e265fb0eb715c0edccf93782bbeab&quot;&gt;1&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;820fd27ae001f2280889480c650e086ef5f31f2a&quot;&gt;2&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;61e2bb7446d241de040d3e0d2cdfaef7cfdb9a8d&quot;&gt;3&lt;&#x2F;a&gt;, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;34556c1fd5c4e9f12a86f762dd4d1654ebbcdf63&quot;&gt;4&lt;&#x2F;a&gt;).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;here-is-some-instructions&quot;&gt;Here is some instructions&lt;a class=&quot;zola-anchor&quot; href=&quot;#here-is-some-instructions&quot; aria-label=&quot;Anchor link for: here-is-some-instructions&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If you uses relative permalinks. It looks like &lt;code&gt;-relative_permalinks: true&lt;&#x2F;code&gt; in &lt;code&gt;config.yml&lt;&#x2F;code&gt;. &lt;em&gt;Delete it!&lt;&#x2F;em&gt;. Because it was removed from Jekyll 3.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Some default plugins of Jekyll 2 (dependencies) are removed out on Jekyll 3. If you want use them. You just add import some Jekyll 2 plugins manually. I used my Jekyll site as a case study.&lt;&#x2F;p&gt;
&lt;p&gt;Add &lt;code&gt;gems&lt;&#x2F;code&gt; and following a list of plugin name what you want in yaml format.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;gems: [jekyll-paginate, jekyll-gist, redcarpet]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can find more removed plugin lists of jekyll 2.x below:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;jekyll-paginate – Jekyll&#x27;s pagination solution from days past&lt;&#x2F;li&gt;
&lt;li&gt;jekyll-coffeescript – processing of CoffeeScript&lt;&#x2F;li&gt;
&lt;li&gt;jekyll-gist – the &lt;code&gt;gist&lt;&#x2F;code&gt; Liquid tag&lt;&#x2F;li&gt;
&lt;li&gt;pygments.rb – the Pygments highlighter&lt;&#x2F;li&gt;
&lt;li&gt;redcarpet – the Markdown processor&lt;&#x2F;li&gt;
&lt;li&gt;toml – an alternative to YAML for configuration files&lt;&#x2F;li&gt;
&lt;li&gt;classifier-reborn – for &lt;code&gt;site.related_posts&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;From &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;jekyllrb.com&#x2F;docs&#x2F;upgrading&#x2F;2-to-3&#x2F;#dropped-dependencies&quot;&gt;Jekyll site&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Jekyll 3 has been changed syntax highlighter to &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;kramdown.gettalong.org&#x2F;&quot;&gt;kramdown&lt;&#x2F;a&gt;.
I&#x27;m using &lt;code&gt;redcarpet&lt;&#x2F;code&gt; in my site because of I don&#x27;t want to change any markdown files to support &lt;code&gt;kramdown&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;In Jekyll 3, It doesn&#x27;t  automatically add a trailing slash (&lt;code&gt;&#x2F;&lt;&#x2F;code&gt;) of permalink (URL).&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If you have custom permalink pages or posts, you should fix all of custom permalink posts and pages. By adding a slash (&lt;code&gt;&#x2F;&lt;&#x2F;code&gt;) at the end of your custom permalinks. (You can see &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;820fd27ae001f2280889480c650e086ef5f31f2a&quot;&gt;my changes&lt;&#x2F;a&gt;) For example:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;permalink: notes&#x2F;vim&lt;&#x2F;code&gt;  change to &lt;code&gt;permalink: notes&#x2F;vim&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;And, you should fix a custom permalink in &lt;code&gt;_config.yml&lt;&#x2F;code&gt; too. You can see in &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;61e2bb7446d241de040d3e0d2cdfaef7cfdb9a8d&quot;&gt;my changes&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;permalink: &#x2F;:categories&#x2F;:title&lt;&#x2F;code&gt; change to &lt;code&gt;permalink: &#x2F;:categories&#x2F;:title&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;lastly&quot;&gt;Lastly&lt;a class=&quot;zola-anchor&quot; href=&quot;#lastly&quot; aria-label=&quot;Anchor link for: lastly&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Here is a part of &lt;code&gt;_config.yml&lt;&#x2F;code&gt; which is changed in Jekyll 3.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;markdown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;        &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;redcarpet&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;gems&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;            &lt;span class=&quot;z-meta z-flow-sequence z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-sequence z-begin z-yaml&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-in z-yaml&quot;&gt;jekyll-paginate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-yaml&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-in z-yaml&quot;&gt;jekyll-gist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-yaml&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-unquoted z-plain z-in z-yaml&quot;&gt;redcarpet&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-sequence z-end z-yaml&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;permalink&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;       &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&#x2F;:categories&#x2F;:title&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Thanks for reading. If you have some questions or suggestions, please comment below.&lt;&#x2F;p&gt;
&lt;p&gt;Bye.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;read-more&quot;&gt;Read more&lt;a class=&quot;zola-anchor&quot; href=&quot;#read-more&quot; aria-label=&quot;Anchor link for: read-more&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&quot;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;jekyllrb.com&#x2F;docs&#x2F;upgrading&#x2F;2-to-3&#x2F;&quot;&gt;Upgrading from 2.x to 3.x&lt;&#x2F;a&gt;&quot; by Official jekyll site&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธีการตั้งค่า VPN ของม.สงขลานครินทร์ (PSU)</title>
		<published>2016-01-31T00:00:00+00:00</published>
		<updated>2016-01-31T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/how-to-setup-vpn-for-psu-th/" type="text/html"/>
		<id>https://thadaw.com/posts/how-to-setup-vpn-for-psu-th/</id>
		<content type="html">&lt;p&gt;เคยไหม ที่อยากจะเข้าถึงข้อมูลบางอย่างเช่น บทความทางวิชาการ เป็นต้น ที่จะต้องเข้าจากอินเตอร์เน็ตในมหาวิทยาลัยเท่านั้น&lt;&#x2F;p&gt;
&lt;p&gt;หรือ ต้องทำงานส่งอาจารย์ และต้องส่งในมหาวิทยาลัยเท่านั้น&lt;&#x2F;p&gt;
&lt;p&gt;หรือ อยากเข้าถึงคอมพิวเตอร์ส่วนตัวของเราในมหาวิทยาลัย (อยู่ในเครือข่ายของมหาวทิยาลัย) ผ่าน &lt;code&gt;ssh&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;แล้วจะทำอย่างไร &lt;strong&gt;คำตอบ&lt;&#x2F;strong&gt; คือ ใช้ &lt;code&gt;VPN&lt;&#x2F;code&gt; สิ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aelw-vpn-khuue-aair&quot;&gt;แล้ว VPN คืออะไร?&lt;a class=&quot;zola-anchor&quot; href=&quot;#aelw-vpn-khuue-aair&quot; aria-label=&quot;Anchor link for: aelw-vpn-khuue-aair&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;VPN ย่อมาจาก Virtual Private Network ซึ่งถ้าแปลเป็นไทยก็คือ เครือข่ายส่วนตัวแบบเสมือน เสมือนก็คือ ไม่ใช่ของจริง แต่มันจะสร้างช่องทางพิเศษไว้สำหรับเราเพียงคนเดียว ที่สามารถเข้าใช้งานช่องทางนี้ได้ เพื่อผ่านไปยังจุดหมายปลาย หรือก็คือ เครือข่ายของมหาวิทยาลัย นั่นเอง เปรียบเสมือนว่า เรากำลังเข้าไปนั่งใช้งานในเครือข่ายของมหาวิทยาลัย&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ภาษาบ้านๆ คือ การเข้าไปนั่งใช้งาน internet ในมหาวิทยาลัย โดยไม่ไม่ต้อง ไปสถานที่นั้นจริงๆ นั่นเอง&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;kaartangkhaa-vpn-samhrab-psu&quot;&gt;การตั้งค่า VPN สำหรับ PSU&lt;a class=&quot;zola-anchor&quot; href=&quot;#kaartangkhaa-vpn-samhrab-psu&quot; aria-label=&quot;Anchor link for: kaartangkhaa-vpn-samhrab-psu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;การตั้งค่าสามารถทำได้ ทุกระบบปฏิบัติการ ไม่ว่าจะเป็น Mac, Windows, Android หรือ iOS&lt;&#x2F;p&gt;
&lt;h3 id=&quot;withiikaartangkhaa-thiilakhant-n&quot;&gt;วิธีการตั้งค่า ทีละขั้นตอน&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiikaartangkhaa-thiilakhant-n&quot; aria-label=&quot;Anchor link for: withiikaartangkhaa-thiilakhant-n&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;สำหรับ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;know.9choo.in.th&#x2F;2013&#x2F;10&#x2F;psu-vpn-windows-881.html&quot;&gt;Windows 8, 8.1, 10 &lt;&#x2F;a&gt; คุณ Choowong Sitaphong ได้เขียนบทความอธิบายไว้อย่างละเอียดแล้ว (&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;know.9choo.in.th&#x2F;2013&#x2F;10&#x2F;psu-vpn-windows-881.html&quot;&gt;วิธีการตั้งค่า PSU VPN Windows 8,8.1 แบบไม่ง้อโปรแกรม&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;สำหรับ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;dmhost2.psu.ac.th&#x2F;~netserv&#x2F;images&#x2F;phocadownload&#x2F;VPN&#x2F;Manual&#x2F;L2TP_AndroidV.4.pdf&quot;&gt;Android&lt;&#x2F;a&gt;
คุณพรพิทักษ์ สันติภาพถาวร ได้เขียนขั้นตอนไว้อย่างละเอียดแล้ว&lt;&#x2F;li&gt;
&lt;li&gt;สำหรับ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;netserv.pn.psu.ac.th&#x2F;upload&#x2F;files&#x2F;doc_wifi&#x2F;VPN_11_Client-Installation_IOS.pdf&quot;&gt;iOS (iPhone, iPad)&lt;&#x2F;a&gt; คุณพรพิทักษ์ สันติภาพถาวร ได้เขียนขั้นตอนไว้อย่างละเอียดแล้ว&lt;&#x2F;li&gt;
&lt;li&gt;สำหรับ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;netserv.pn.psu.ac.th&#x2F;upload&#x2F;files&#x2F;doc_lan&#x2F;VPN_10_Client-Installation_MAC10.5.pdf&quot;&gt;Mac OS 10.5 Leopard&lt;&#x2F;a&gt; คุณพรพิทักษ์ สันติภาพถาวร ได้เขียนขั้นตอนไว้อย่างละเอียดแล้ว&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;parameter-taang-thiiaichainkaartangkhaaainkaaraichngaan&quot;&gt;Parameter ต่างๆ ที่ใช้ในการตั้งค่าในการใช้งาน&lt;a class=&quot;zola-anchor&quot; href=&quot;#parameter-taang-thiiaichainkaartangkhaaainkaaraichngaan&quot; aria-label=&quot;Anchor link for: parameter-taang-thiiaichainkaartangkhaaainkaaraichngaan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Name                 : PSU
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Type                 : L2TP&#x2F;IPSec PSK
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Server address       : vpn.psu.ac.th
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;IPSEC pre-shared key : vpn key
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ทริคการใช้ git: การ merge บางไฟล์ไปอีก branch</title>
		<published>2016-01-30T00:00:00+00:00</published>
		<updated>2016-01-30T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/git-trick-how-to-merge-some-files-from-other-branch-th/" type="text/html"/>
		<id>https://thadaw.com/posts/git-trick-how-to-merge-some-files-from-other-branch-th/</id>
		<content type="html">&lt;p&gt;มีหลายๆ เทคนิคที่สามารถทำได้ วิธีนี้เป็นวิธีที่ง่ายที่สุด ซึ่งผมได้นำมาจากบทความของ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;jasonrudolph.com&#x2F;blog&#x2F;2009&#x2F;02&#x2F;25&#x2F;git-tip-how-to-merge-specific-files-from-another-branch&#x2F;&quot;&gt;jasonrudolph.com&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;นั่นคือ ใช้ประโยชน์จาก &lt;code&gt;git checkout&lt;&#x2F;code&gt; นั่นเอง&lt;&#x2F;p&gt;
&lt;p&gt;สมมติว่า ผมมี 2 branches คือ &lt;code&gt;master&lt;&#x2F;code&gt; และ &lt;code&gt;mildronize-dotfiles&lt;&#x2F;code&gt; ตามผลลัพธ์ด้านล่าง ผมต้องการที่จะ merge ไฟล์ &lt;code&gt;README.md&lt;&#x2F;code&gt; จาก &lt;code&gt;mildronize-dotfiles&lt;&#x2F;code&gt; ไปยัง &lt;code&gt;master&lt;&#x2F;code&gt;
และทำการ commit ให้เรียบร้อย&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git branch&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;master&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mildronize-dotfiles&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นทำการย้าย branch ไปยัง &lt;code&gt;master&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git checkout master&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนั้นใช้ &lt;code&gt;git checkout&lt;&#x2F;code&gt; เพื่อขอไฟล์ &lt;code&gt;README.md&lt;&#x2F;code&gt; จาก branch ของ &lt;code&gt;mildronize-dotfiles&lt;&#x2F;code&gt;
มายัง branch ปัจจุบัน (นั่นคือ &lt;code&gt;master&lt;&#x2F;code&gt;)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git checkout mildronize-dotfiles README.md&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git status&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;On&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; branch master&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Your&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; branch is up-to-date with &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;origin&#x2F;master&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Changes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; to be committed:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-compound z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;use&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;git reset HEAD &amp;lt;file&amp;gt;...&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; to unstage&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;modified:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   README.md&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;สังเกตุได้ว่า เมื่อใช้ &lt;code&gt;git status&lt;&#x2F;code&gt; ตรวรจสอบดูจะพบว่า ไฟล์ &lt;code&gt;README.md&lt;&#x2F;code&gt; ได้ถูกแก้ไขแล้ว
จากนั้นก็ commit ให้เรียบร้อย เป็นอันเสร็จสิ้นครับ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; git commit&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;m&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Merge readme into master branch&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;จากนี้จะทำการ &lt;code&gt;push&lt;&#x2F;code&gt; หรืออะไรต่อก็แล้วแต่เลยครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>How to Use Vim with Clipboard on Debian</title>
		<published>2015-09-09T00:00:00+00:00</published>
		<updated>2015-09-09T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/how-to-use-vim-with-clipboard-on-debian/" type="text/html"/>
		<id>https://thadaw.com/posts/how-to-use-vim-with-clipboard-on-debian/</id>
		<content type="html">&lt;h2 id=&quot;instructions&quot;&gt;Instructions&lt;a class=&quot;zola-anchor&quot; href=&quot;#instructions&quot; aria-label=&quot;Anchor link for: instructions&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install extra package that can complete more features on Vim with GUI. There many packages are available on the repository. That is &lt;code&gt;vim-athena&lt;&#x2F;code&gt;, &lt;code&gt;vim-gnome&lt;&#x2F;code&gt;, &lt;code&gt;vim-gtk&lt;&#x2F;code&gt; and &lt;code&gt;vim-nox&lt;&#x2F;code&gt;. In this case, I have used &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.xfce.org&#x2F;&quot;&gt;Xfce&lt;&#x2F;a&gt; which applies GTK GUI. I will install &lt;code&gt;vim-gtk&lt;&#x2F;code&gt; for enable clipboard feature and others. For &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.gnome.org&#x2F;&quot;&gt;Gnome&lt;&#x2F;a&gt; user, you should installing &lt;code&gt;vim-gnome&lt;&#x2F;code&gt;. &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;packages.debian.org&#x2F;search?keywords=vim&quot;&gt;Read more&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo aptitude install vim-gtk&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Now, you will found &lt;code&gt;+&lt;&#x2F;code&gt; registers in &lt;code&gt;:reg&lt;&#x2F;code&gt; in Vim. Trick is use Vim
registers&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&quot;+yy&lt;&#x2F;code&gt; for yank to &lt;code&gt;+&lt;&#x2F;code&gt; register which is binding to clipboard&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&quot;+p&lt;&#x2F;code&gt; (Normal mode) for paste from &lt;code&gt;+&lt;&#x2F;code&gt; register which is binding to clipboard&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Ctrl r&lt;&#x2F;code&gt; &lt;code&gt;+&lt;&#x2F;code&gt; (Insert mode) for paste from &lt;code&gt;+&lt;&#x2F;code&gt; register which is binding to clipboard&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;how-to-use-registers-in-vim&quot;&gt;How to use registers in Vim&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-to-use-registers-in-vim&quot; aria-label=&quot;Anchor link for: how-to-use-registers-in-vim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Show a list of registers&lt;&#x2F;strong&gt;: press &lt;code&gt;:reg&lt;&#x2F;code&gt; in normal mode&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Access Vim registers&lt;&#x2F;strong&gt;: Press &lt;code&gt;&quot;&lt;&#x2F;code&gt; and following &lt;em&gt;name of register&lt;&#x2F;em&gt;.
Ex.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&quot;0&lt;&#x2F;code&gt; for accessing &lt;code&gt;0&lt;&#x2F;code&gt; register&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&quot;+&lt;&#x2F;code&gt; for accessing &lt;code&gt;+&lt;&#x2F;code&gt; register&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vim registers use&lt;&#x2F;strong&gt;: Press &lt;code&gt;&quot;&lt;&#x2F;code&gt; &lt;code&gt;[name]&lt;&#x2F;code&gt; and vim command. Ex.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&quot;0yy&lt;&#x2F;code&gt; means to yank to &lt;code&gt;0&lt;&#x2F;code&gt; register&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&quot;5yy&lt;&#x2F;code&gt; means to yank to &lt;code&gt;5&lt;&#x2F;code&gt; register&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&quot;5p&lt;&#x2F;code&gt; means to paste from &lt;code&gt;5&lt;&#x2F;code&gt; register&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For more detail about Vim register, I will write a post later.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;a class=&quot;zola-anchor&quot; href=&quot;#links&quot; aria-label=&quot;Anchor link for: links&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;11489440&quot;&gt;How to make vim paste from (and copy to) system&#x27;s clipboard? from stackoverflow&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Mildy: My Debian customization</title>
		<published>2015-09-08T00:00:00+00:00</published>
		<updated>2015-09-08T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/mildy-my-debian-customization/" type="text/html"/>
		<id>https://thadaw.com/posts/mildy-my-debian-customization/</id>
		<content type="html">&lt;p&gt;Are you boring in Desktop of Debian. Here are some configurations for
making your Debian to good look Debian.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: This post is only configuration that I&#x27;m used to customize
my desktop. It isn&#x27;t suitable for beginner. I may write a post for
beginner in the future. If you have any question about this, please
contact me following in &lt;code&gt;About&lt;&#x2F;code&gt; menu.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;easy-instruction-for-customizing-linux-desktop&quot;&gt;Easy instruction for customizing linux desktop&lt;a class=&quot;zola-anchor&quot; href=&quot;#easy-instruction-for-customizing-linux-desktop&quot; aria-label=&quot;Anchor link for: easy-instruction-for-customizing-linux-desktop&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;Choose a desktop environment&lt;&#x2F;li&gt;
&lt;li&gt;Choose a theme&lt;&#x2F;li&gt;
&lt;li&gt;Install some packages for best experience&lt;&#x2F;li&gt;
&lt;li&gt;Config something&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is my Linux desktop&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;mildy-my-debian-customization&#x2F;2015-09-08-mildy-my-debian-customization.jpg&quot; alt=&quot;mildy-my-debian-customizing-screenshot&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;my-customizatioan&quot;&gt;My customizatioan&lt;a class=&quot;zola-anchor&quot; href=&quot;#my-customizatioan&quot; aria-label=&quot;Anchor link for: my-customizatioan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Desktop environment: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.xfce.org&#x2F;&quot;&gt;Xfce&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Theme ( Recommended GTK 2.0):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;code&gt;Appearance&lt;&#x2F;code&gt;:
&lt;ul&gt;
&lt;li&gt;Style: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;gnome-look.org&#x2F;content&#x2F;show.php&#x2F;?content=144237&quot;&gt;Adwaita&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Icons: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;gnome-look.org&#x2F;content&#x2F;show.php&#x2F;?content=128143&quot;&gt;Faenza&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;In &lt;code&gt;Window Manager&lt;&#x2F;code&gt;:
&lt;ul&gt;
&lt;li&gt;Style: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;xfce-look.org&#x2F;content&#x2F;show.php&#x2F;axiom+xfwm?content=90145&quot;&gt;axiom&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Extra package:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Dock: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;launchpad.net&#x2F;plank&quot;&gt;Plank&lt;&#x2F;a&gt; (which is used in &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;elementary.io&#x2F;&quot;&gt;Elementary OS&lt;&#x2F;a&gt; )&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In Debian, Plank is now available on testing and sid only, &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;packages.debian.org&#x2F;plank&quot;&gt;see more&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Items in &lt;code&gt;Panel&lt;&#x2F;code&gt; on Xfce:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Separator: style=Transparent, expand=true&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Separator: style=Transparent, expand=true&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Clock: Format=Custom Format (&lt;code&gt;%I:%M %p | %a %d %b %Y&lt;&#x2F;code&gt;)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Separator: style=Transparent, expand=true&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Workspace Switcher&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Keyboard Layouts&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Notification Area: Show frame=false&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Audio Mixer&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Action Buttons&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Separator: style=Separator&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Applications Menu&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Show Desktop&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;4 items first in the items of Xfce panel is a technique to adjust center position
of clock&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;terminal&quot;&gt;Terminal&lt;a class=&quot;zola-anchor&quot; href=&quot;#terminal&quot; aria-label=&quot;Anchor link for: terminal&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;use &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;ethanschoonover.com&#x2F;solarized&quot;&gt;Solarized&lt;&#x2F;a&gt; color scheme&lt;&#x2F;li&gt;
&lt;li&gt;Combine many programs in terminal:
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.zsh.org&#x2F;&quot;&gt;Zsh&lt;&#x2F;a&gt; and &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;robbyrussell&#x2F;oh-my-zsh&quot;&gt;Oh my Zsh&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;tmux.github.io&#x2F;&quot;&gt;Tmux&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.vim.org&#x2F;&quot;&gt;Vim&lt;&#x2F;a&gt; and
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlhuda&#x2F;janus&quot;&gt;Janus&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;All configuration of this section is stored at
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;dotfiles&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;dotfiles&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;More details of this section can see in &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;dev.mildronize.com&#x2F;th&#x2F;notes&#x2F;vim-janus-tmux&#x2F;&quot;&gt;my
post&lt;&#x2F;a&gt; (Thai
version)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>How to Compile &amp; Install Gnome Builder on Debian</title>
		<published>2015-07-02T00:00:00+00:00</published>
		<updated>2015-07-02T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/how-to-compile-and-install-gnome-builder-on-debian/" type="text/html"/>
		<id>https://thadaw.com/posts/how-to-compile-and-install-gnome-builder-on-debian/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;Note: This post is early access for using Gnome Builder. It may be including some bug or any error, please calm when you found some bug. So I think this is becoming the best editor for gnome user, Cheer!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I have heard about &lt;code&gt;gnome builder&lt;&#x2F;code&gt; announcement on &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.indiegogo.com&#x2F;projects&#x2F;builder-an-ide-of-our-gnome#&#x2F;story&quot;&gt;Indiegogo&lt;&#x2F;a&gt; in some blog (I can&#x27;t remember that). It is very interesting for me. Because it is made for Gnome user, and me too. It do not tell it anymore, let&#x27;s watch belowing video to introduce &lt;code&gt;Gnome Builder&lt;&#x2F;code&gt;. Read more about the feature of Gnome Builder via &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;wiki.gnome.org&#x2F;Apps&#x2F;Builder&#x2F;Features&quot;&gt;https:&#x2F;&#x2F;wiki.gnome.org&#x2F;Apps&#x2F;Builder&#x2F;Features&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;jXEjYu0SJ3A&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;&#x2F;iframe&gt;
&lt;p&gt;Okay, I can&#x27;t wait to try it. Let&#x27;s go to compile &amp;amp; install it!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;a class=&quot;zola-anchor&quot; href=&quot;#installation&quot; aria-label=&quot;Anchor link for: installation&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install some prerequisite packages for Gnome Builder.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo aptitude install intltool gtk-doc-tools libgtksourceview-3.0-dev libdevhelp-dev libgit2-glib-1.0-dev libgjs-dev python-gobject-dev llvm-dev libclang-dev python3-dev&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Go to &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;git.gnome.org&#x2F;browse&#x2F;gnome-builder&#x2F;&quot;&gt;Gnome git repository home&lt;&#x2F;a&gt;, and select the lastest version of Gnome Builder or any version what you want. In my case, I choose &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;git.gnome.org&#x2F;browse&#x2F;gnome-builder&#x2F;snapshot&#x2F;GNOME_BUILDER_3_16_3.tar.xz&quot;&gt;GNOME_BUILDER_3_16_3&lt;&#x2F;a&gt; to download it.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Extract the compression file (GNOME_BUILDER_3_16_3.tar.xz), using this command below (It can use only .tar.xz only)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; tar&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;Jxvf&lt;&#x2F;span&gt; GNOME_BUILDER_3_16_3.tar.xz&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;go to the directory which you extracted&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; cd GNOME_BUILDER_3_16_3&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Execute &lt;code&gt;autogen.sh&lt;&#x2F;code&gt; and run &lt;code&gt;make&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; .&#x2F;autogen.sh&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; make&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;All done!, Let&#x27;s enjoy the editor on our Gnome&lt;&#x2F;p&gt;
&lt;p&gt;Next post, I will post how I know the prerequisite packages for compiling C source.&lt;&#x2F;p&gt;
&lt;p&gt;Bye.&lt;&#x2F;p&gt;
&lt;p&gt;Special Thank Thanathip Limna for his suggestion&lt;&#x2F;p&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;a class=&quot;zola-anchor&quot; href=&quot;#resources&quot; aria-label=&quot;Anchor link for: resources&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;wiki.gnome.org&#x2F;Apps&#x2F;Builder&quot;&gt;Gnome Builder Home page&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.indiegogo.com&#x2F;projects&#x2F;builder-an-ide-of-our-gnome#&#x2F;story&quot;&gt;Indiegogo Funding&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธีการทำให้ Gnome Nautilus แสดง directory ก่อนไฟล์</title>
		<published>2015-07-01T00:00:00+00:00</published>
		<updated>2015-07-01T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/gnome-nautilus-sort-directories-before-files/" type="text/html"/>
		<id>https://thadaw.com/posts/gnome-nautilus-sort-directories-before-files/</id>
		<content type="html">&lt;p&gt;พอดีผมใช้ Windows มาก่อนแล้วถนัดให้ แสดง folder ก่อนแสดงไฟล์ เลยไปหาวิธีการมาจาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;gexperts.com&#x2F;wp&#x2F;gnome-3-12-filesnautilus-sort-folders-before-files-issues&#x2F;&quot;&gt;เว็บนี้&lt;&#x2F;a&gt;
วันนี้เลยเอามาแปล และมาอธิบายให้ฟัง&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;หมายเหตุ&lt;&#x2F;strong&gt;: ใน Windows เค้าเรียกว่า Folder ส่วนใน linux เค้าจะเรียกว่า directory ครับ&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ผมใช้ GNOME รุ่น 3.16 แต่ในเว็บนั้นบอกรุ่น 3.12 แต่ผมลองแล้วใช้งานได้เลยนำมาแบ่งปันกัน&lt;&#x2F;p&gt;
&lt;h2 id=&quot;khant-nthii-1&quot;&gt;ขั้นตอนที่ 1&lt;a class=&quot;zola-anchor&quot; href=&quot;#khant-nthii-1&quot; aria-label=&quot;Anchor link for: khant-nthii-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;ให้ไปที่โปรแกรม &lt;code&gt;dconf-editor&lt;&#x2F;code&gt; ถ้าหาไม่เจอให้กดปุ่ม start หรือ นำเม้าส์ไปไว้ที่มุมบนขวานะครับ แล้วพิมพ์ชื่อโแกรมลงไป แล้วกด Enter คับ&lt;&#x2F;li&gt;
&lt;li&gt;จะขึ้นหน้าต่างใหม่ขึ้นมา มันจะมีสองฝั่ง โดยเริ่มจากฝั่งซ้ายก่อน คลิกไปที่ &lt;code&gt;org&lt;&#x2F;code&gt; ครับ&lt;&#x2F;li&gt;
&lt;li&gt;จากนั้นไปที่ &lt;code&gt;gnome&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;แล้วก็ &lt;code&gt;nautilus&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;แล้วก็ &lt;code&gt;preferences&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;เมื่อกด ที่ preferences จากขั้นตอนที่ 5 แล้ว ให้มองไปทางฝั่งขวา แล้วหารายการที่มีชื่อว่า &lt;code&gt;sort-directories-first&lt;&#x2F;code&gt; แล้วกดติ๊กถูกครับ&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ถ้าขั้นตอนแรกยังไม่ได้ ให้ทำขั้นตอนที่ 2 อีกครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;khant-nthii-2&quot;&gt;ขั้นตอนที่ 2&lt;a class=&quot;zola-anchor&quot; href=&quot;#khant-nthii-2&quot; aria-label=&quot;Anchor link for: khant-nthii-2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;ทำเหมือน ขั้นตอนที่ 1 ข้อที่ 1 เลย&lt;&#x2F;li&gt;
&lt;li&gt;ดูฝั่งทางซ้าย ไปที่ &lt;code&gt;org&lt;&#x2F;code&gt; แล้วก็ &lt;code&gt;gtk&lt;&#x2F;code&gt; แล้วก็ &lt;code&gt;Settings&lt;&#x2F;code&gt; แล้วก็ &lt;code&gt;file-chooser&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;จากนี่น ดูฝั่งขวา แล้วหารายการที่มีชื่อว่า &lt;code&gt;sort-directories-first&lt;&#x2F;code&gt; แล้วกดติ๊กถูกครับ&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ถ้าตั้งค่าตามที่กล่าวมานี้แล้ว สำหรับผมแล้วทำใช้งานได้ครับ
ขอบคุณครับ&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>มือใหม่หัดใช้ลินุกซ์ครั้งแรก</title>
		<published>2015-06-26T00:00:00+00:00</published>
		<updated>2015-06-26T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/becoming-newbie-linux-user/" type="text/html"/>
		<id>https://thadaw.com/posts/becoming-newbie-linux-user/</id>
		<content type="html">&lt;p&gt;โพสนี้เป็นการรวมเรื่องราวกันหัดใช้ linux ครั้งแรกของผมโดย จะแบ่งเป็นข้อๆ และก็จะค่อยๆ ทยอยเขียน
ทีละบทความ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;khwaamphyaayaamkh-ngphmthiicchahadaich-linux-maamaakkwaa-10-khrang&quot;&gt;ความพยายามของผมที่จะหัดใช้ linux มามากกว่า 10 ครั้ง&lt;a class=&quot;zola-anchor&quot; href=&quot;#khwaamphyaayaamkh-ngphmthiicchahadaich-linux-maamaakkwaa-10-khrang&quot; aria-label=&quot;Anchor link for: khwaamphyaayaamkh-ngphmthiicchahadaich-linux-maamaakkwaa-10-khrang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;ครั้งแรกกับ Linux&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ผมติด Windows มากในสมัยเด็กๆ เพราะไม่ว่าจะมองไปทางไหนๆ ก็มีแต่คนใช้ Windows ที่มีหน้าตาที่
สวยงาม แต่แล้วสมัยตอนอยู่เรียนมัธยมต้น ก็ได้ยินข่าวเกี่ยวกับ Linux บ้างและอยากลองใช้ ผมพยายามติดตั้ง
และลองใช้งาน linux เป็นครั้งแรก โดยเลือกลง
เป็น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.ubuntu.com&#x2F;download&#x2F;desktop&quot;&gt;Ubuntu desktop&lt;&#x2F;a&gt;
พยายามลองใช้งานในโหมดของเป็นกราฟฟิคโหมด (GUI Mode) แต่แล้วก็พบว่า ไม่คุ้นชินกับหน้าตาและวิธี
การใช้งานเลย รวมถึงโปรแกรมต่างๆ ที่ใช้อยู่ใน windows ปกติก็ไม่มีให้ใช้ เลยสุดท้ายก็ถอดใจไปกลับไปใช้
Windows เหมือนเดิม&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ครั้งต่อๆ มา กับ Linux&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ในช่วงเวลาหลายปีที่ผ่านมาตั้งแต่ มัธยมต้นนั้นได้ พยายามลงและลองใช้ linux อยู่หลายครั้ง แต่ก็ยังไม่
เข้าใจถึงลักษณะการทำงาน และ วิธีใช้ รวมถึงวิธีการแก้ปัญหา ต่างๆ พอประสบปัญหาครั้งหนึี่งก็แก้ไม่ถูก
สุดท้ายก็แก้ไม่ถูก กับการที่ไม่มีโปแกรมที่คุ้นเคยเลย เลยทำให้ถอดใจไปอย่างมาก&lt;&#x2F;p&gt;
&lt;p&gt;แต่หลังจากที่ขึ้นมหาวิทยาลัยมา บวกกับในยุคสมัยที่มีโปรแกรม Cross Platform เกิดขึ้นมาเยอะมากทำให้
สามารถใช้งานได้ ค่อนข้างโอเคเลย บวกกับมีคนช่วยสอน ช่วยแนะนำการใช้งานให้ ต้องขอบคุณพี่
Thanathip Limna ที่ช่วยแนะนำหลายๆ เรื่อง&lt;&#x2F;p&gt;
&lt;p&gt;จนสุดท้ายก็เลยนำปัญหาที่ผมพบระหว่างการเริ่มหัดใช้งาน linux มาเขียนเป็นบทความอธิบายๆ การใช้ และ
ปัญหารวมถึงวิธีการแก้ปัญหาเป็นส่วนๆ ไป ตามหัวข้อด้านล่าง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;khuumuue-kaaraichngaan-linux-chbabaich-debian-epnkrniisueksaa&quot;&gt;คู่มือการใช้งาน Linux ฉบับใช้ Debian เป็นกรณีศึกษา&lt;a class=&quot;zola-anchor&quot; href=&quot;#khuumuue-kaaraichngaan-linux-chbabaich-debian-epnkrniisueksaa&quot; aria-label=&quot;Anchor link for: khuumuue-kaaraichngaan-linux-chbabaich-debian-epnkrniisueksaa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;ลินุกซ์คืออะไร&lt;&#x2F;li&gt;
&lt;li&gt;Linux distrubtion ไหนที่คุณชอบ เลือกมาหนึ่ง แล้วหัดใช้มัน&lt;&#x2F;li&gt;
&lt;li&gt;การติดตั้ง Debian&lt;&#x2F;li&gt;
&lt;li&gt;การใช้งานลินุกซ์ครั้งแรก&lt;&#x2F;li&gt;
&lt;li&gt;ทำความเข้าใจเกี่ยวกับ Debian ซึ่งเป็นหนึ่งใน Linux distrubtion&lt;&#x2F;li&gt;
&lt;li&gt;[ทำความเข้าใจเกี่ยวแต่ละรุ่นของ Debian]({{ &#x2F;posts&#x2F;2015-06-25-what-is-debian-version-sid-testing-stable&#x2F; | url }})&lt;&#x2F;li&gt;
&lt;li&gt;[อัพเกรด Debian จาก stable เป็น sid]({{ &#x2F;posts&#x2F;2015-06-08-upgrade-debian-to-sid | url  }})&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;หัวข้อที่สำคัญ&lt;&#x2F;strong&gt;: เราจะแก้ปัญหาอย่างไรที่พบระหว่างการติดตั้ง packages โดยที่สามารถเรียนรู้จากกรณีศึกษาด้านล่างนี้
&lt;ul&gt;
&lt;li&gt;[กรณีศึกษาที่ 1: การติดตั้ง Google Chrome บน Debian]({{ &#x2F;posts&#x2F;2015-06-22-how-to-install-google-chrome-on-debian | url }})&lt;&#x2F;li&gt;
&lt;li&gt;กรณีศึกษาที่ 2: การติดตั้ง Bracket บน Debian&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;บำรุงรักษาและพยายามที่จะเรียนรู้สิ่งใหม่ๆ ตลอดเวลา&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>เวอร์ชั่นแต่ละเวอร์ชั่นของ debian คืออะไร อะไรคือ sid, testing, stable โอ๊ยเยอะแยะไปหมด...</title>
		<published>2015-06-25T00:00:00+00:00</published>
		<updated>2015-06-25T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/what-is-debian-version-sid-testing-stable/" type="text/html"/>
		<id>https://thadaw.com/posts/what-is-debian-version-sid-testing-stable/</id>
		<content type="html">&lt;p&gt;สวัสดีครับ คุณผู้อ่านทุกท่านที่สนใจใน Debian&lt;&#x2F;p&gt;
&lt;p&gt;ก่อนเริ่มกันผมขอเริ่มเกรินก่อนว่า คำถามนี้ (เวอร์ชั่นแต่ละอันของ debian คืออะไร อะไรคือ sid, testing, stable โอ๊ยเยอะไปหมด….) เป็นคำแรกๆ ที่เกิดขึ้นในหัวของผม ตั้งแต่ใช้ Debian แรกๆ ว่าอะไรกันหนักหนา เยอะแยะไปหมด งงไปหมด เริ่มยังไงดี เริ่มไม่ถูก แล้วเราใช้ๆ ไปมันจะพังมั้ย โอ๊ย สารพัดคำถาม  ถาโถมเข้ามาจน เลิกใช้ linux ไปหลายรอบ เอาหละ เข้าเรื่อง กันดีกว่า เราจะมาตอบคำถามหล่าวนี้กัน (อาจจะถูกผิดบ้าง ตามภาษาคนเพิ่งหัดใช้)&lt;&#x2F;p&gt;
&lt;p&gt;เวอร์ชั่นของ Debian เค้าเรียกว่า Releases ซึ่งเป็นสถานะของการพัฒนา Debian ที่อยู่ในระหว่างการพัฒนา คือ stable , testing, unstable&lt;&#x2F;p&gt;
&lt;h2 id=&quot;eraamaaduukandiikwaa-waaaetla-ankhuue-aairkanbaang&quot;&gt;เรามาดูกันดีกว่า ว่าแต่ละอันคืออะไรกันบ้าง&lt;a class=&quot;zola-anchor&quot; href=&quot;#eraamaaduukandiikwaa-waaaetla-ankhuue-aairkanbaang&quot; aria-label=&quot;Anchor link for: eraamaaduukandiikwaa-waaaetla-ankhuue-aairkanbaang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;releases&#x2F;stable&#x2F;&quot;&gt;Stable&lt;&#x2F;a&gt;  คือ เวอร์ชั่นที่มีความเสถียร นั่นเอง นั่นหมายความว่า ไม่มีข้อผิดพลาด (ถึงมีก็น้อยมากๆ) หรือบั๊ก เลย ดังนั้นจึงเหมาะมากสำหรับการนำมาทำเป็น server เพราะมันเสถียรนั้นเอง&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;releases&#x2F;testing&#x2F;&quot;&gt;testing&lt;&#x2F;a&gt; คือ เวอร์ชั่นทดสอบ(แปลจากชื่อ) มันคือ เวอร์ชั่นหลักที่ใหม่ กว่า Stable (ในที่นี้คือ Wheezy) เรียกว่า Jessie แต่อยู่ในระหว่างการพัฒนาอาจจะมีบั๊กบ้างอะไรบ้าง เล็กๆ น้อยๆ แต่ระบบจะมีความใหม่ของ โปรแกรม(เค้าชอบเรีียกกันว่า package) กว่า stable นั่นเอง  ซึ่ง โปรแกรม จะอยู่ใน unstable เป็นระยะเวลานึง ถึงจะถูกย้ายเข้ามาอยู่ ใน testing นั่นหมายความว่า พวกบั๊กต่างๆ ที่ร้ายแรงจะถูกแก้ใน เวอร์ชั่นของ unstable หมดแล้ว&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;releases&#x2F;unstable&#x2F;&quot;&gt;unstable&lt;&#x2F;a&gt; หรือก็คือ sid คือ เวอร์ชั่นที่ไม่เสถียร (แปลจากชื่อ) โปรแกรมที่อยู่ในช่วงกำลังพัฒนา และสามารถทำงานได้แล้วจะถูกอัพโหลดเข้ามาอยู่ใน unstable ดังนั้นอาจจะมีบั๊ก (ไม่ต้องตกใจ) ดังนั้นผู้ใช้ unstable ส่วนใหญ่จะเป็นนักพัฒนาหรือ พวกอยากลองของใหม่ๆ และแน่นอน มันมักจะมีบั๊กเสมอ พวกเค้าก็จะต้องช่วยส่งบั๊กพวกนี้ให้กับ ทีมพัฒนาโปรแกรมนั้นๆ ต่อไป จนบั๊กๆ ที่ร้ายแรงต่างๆ ได้ถูกแก้จนหมดแล้วถึงจะถูกนำไปไว้ใน testing อย่างที่อธิบายไว้แล้วข้างต้น&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ทั้ง Stable, Testing และ unstable เป็น Repository (ที่สำหรับเก็บโค๊ด) ที่ไม่มีทางตาย เอ๊ะยังไง&lt;&#x2F;p&gt;
&lt;p&gt;– &lt;strong&gt;Stable&lt;&#x2F;strong&gt; ตอนนี้ คือ Wheezy (Debian 7)  นั้นหมายความว่า เมื่อเวอร์ชั่นถัดไปของ debian (Jessie)  เสถียรแล้ว จะถูกนำมาแทน ที่ Wheezy นั้นเอง  ดังนั้นค่าของคำว่า stable จะถูกเปลี่ยนไป เรื่อยๆ&lt;&#x2F;p&gt;
&lt;p&gt;– &lt;strong&gt;Testing&lt;&#x2F;strong&gt; ตอนนี้ คือ Jessie นั้นหมายความ เมื่อใดที่ Jessie เสถียรแล้ว Testing ก็จะเปลี่ยนเป็นชื่อใหม่ (ยังไม่ตั้งที) เป็นเวอร์ชั่นถัดไปของ Jessie อีกที&lt;&#x2F;p&gt;
&lt;p&gt;– &lt;strong&gt;Unstable&lt;&#x2F;strong&gt; เมื่อ testing ในปัจจุบัน กลายเป็น stable , unstable ก็จะเป็นอะไรที่ใหม่กว่า testing&lt;&#x2F;p&gt;
&lt;p&gt;ค่าของ Stable, Testing และ unstable จะถูกไปเรื่อยๆ ตามเวอร์ชั่นของ Debian ที่ใหม่ขึ้นเรื่อยๆ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aelwew-rchanthanghmdkh-ng-debian-mii-aairbaang&quot;&gt;แล้วเวอร์ชั่นทั้งหมดของ Debian มีอะไรบ้าง&lt;a class=&quot;zola-anchor&quot; href=&quot;#aelwew-rchanthanghmdkh-ng-debian-mii-aairbaang&quot; aria-label=&quot;Anchor link for: aelwew-rchanthanghmdkh-ng-debian-mii-aairbaang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;เวอร์ชั่นที่ใหม่ที่สุด เรียกว่า sid (หรือ unstable นั่นเอง )&lt;&#x2F;li&gt;
&lt;li&gt;เวอร์ชั่นถัดไปของ debian คือ stretch — ยังไม่เสถียร&lt;&#x2F;li&gt;
&lt;li&gt;Debian 8.0 (jessie) — เวอร์ชั่นเสถียร ณ ตอนนี้&lt;&#x2F;li&gt;
&lt;li&gt;Debian 7.0 (wheezy) — เสถียรและก็เก่าแล้ว&lt;&#x2F;li&gt;
&lt;li&gt;Debian 6.0 (squeeze) — เสถียรและก็เก่าแล้ว&lt;&#x2F;li&gt;
&lt;li&gt;Debian GNU&#x2F;Linux 5.0 (lenny) — เสถียรและก็เก่าแล้ว&lt;&#x2F;li&gt;
&lt;li&gt;Debian GNU&#x2F;Linux 4.0 (etch) — เสถียรและก็เก่าแล้ว&lt;&#x2F;li&gt;
&lt;li&gt;Debian GNU&#x2F;Linux 3.1 (sarge) — เสถียรและก็เก่าแล้ว&lt;&#x2F;li&gt;
&lt;li&gt;Debian GNU&#x2F;Linux 3.0 (woody) — เสถียรและก็เก่าแล้ว&lt;&#x2F;li&gt;
&lt;li&gt;Debian GNU&#x2F;Linux 2.2 (potato) — เสถียรและก็เก่าแล้ว&lt;&#x2F;li&gt;
&lt;li&gt;Debian GNU&#x2F;Linux 2.1 (slink) — เสถียรและก็เก่าแล้ว&lt;&#x2F;li&gt;
&lt;li&gt;Debian GNU&#x2F;Linux 2.0 (hamm) — เสถียรและก็เก่าแล้ว&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;และก็จบกันไปแล้วนะครับ หวังว่าจะได้รับความรู้ไม่มากก็น้อย&lt;&#x2F;p&gt;
&lt;p&gt;จาก &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;releases&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.debian.org&#x2F;releases&#x2F;&lt;&#x2F;a&gt; และต้องขอบคุณพี่  Thanathip Limna ที่ช่วยแนะให้ในหลายๆ อย่าง&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>วิธีการติดตั้ง Google Chrome บน Debian</title>
		<published>2015-06-22T00:00:00+00:00</published>
		<updated>2015-06-22T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/how-to-install-google-chrome-on-debian-th/" type="text/html"/>
		<id>https://thadaw.com/posts/how-to-install-google-chrome-on-debian-th/</id>
		<content type="html">&lt;h2 id=&quot;deprecated-post&quot;&gt;*Deprecated post!&lt;a class=&quot;zola-anchor&quot; href=&quot;#deprecated-post&quot; aria-label=&quot;Anchor link for: deprecated-post&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Please go to &lt;a href=&quot;&#x2F;a-very-short-ubuntu-debian-packages-installation-sheet-0967oym&#x2F;&quot;&gt;my new post&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;singthiicchamepnt-kaartidtang&quot;&gt;สิ่งที่จำเป็นต่อการติดตั้ง&lt;a class=&quot;zola-anchor&quot; href=&quot;#singthiicchamepnt-kaartidtang&quot; aria-label=&quot;Anchor link for: singthiicchamepnt-kaartidtang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ควรจะลง &lt;code&gt;Chromium&lt;&#x2F;code&gt; ก่อน เพราะว่าใน Chromium มี package ที่จำเป็นต่อการลง &lt;code&gt;Google Chrome&lt;&#x2F;code&gt; โดยใช้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo aptitude install chromium&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;หมายเหตุ:&lt;&#x2F;strong&gt; ความจริงจะลงเฉพาะ package ที่ Google Chrome ต้องการก็ได้ แต่จำไม่ได้แล้วว่ามันต้องการอะไรบ้าง เลยลงทั้ง Chromium เลย สะดวกดี&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;khant-nkaartidtang&quot;&gt;ขั้นตอนการติดตั้ง&lt;a class=&quot;zola-anchor&quot; href=&quot;#khant-nkaartidtang&quot; aria-label=&quot;Anchor link for: khant-nkaartidtang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;เริ่มจากจาก เพิ่ม repository ของ Google Chrome โดยที่เป็น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;wiki.debian.org&#x2F;UnofficialRepositories&quot;&gt;repository แบบไม่เป็นทางการ&lt;&#x2F;a&gt;  แต่ก็สามารถเชื่อถือได้ระดับนึง เพราะว่าเป็น repository ที่แนะนำโดย Debian และเป็นของ Google&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;wiki.debian.org&#x2F;DebianRepository&quot;&gt;repository&lt;&#x2F;a&gt; คือ แหล่งที่เก็บซอฟแวร์สำหรับ การติดตั้งใน linux ซึ่งสามารถค้นหาซอฟแวร์เพื่อที่จะติดตั้งได้&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;สามารถทำได้ โดย เพิ่มประโยคว่า  &lt;code&gt;deb http:&#x2F;&#x2F;dl.google.com&#x2F;linux&#x2F;chrome&#x2F;deb&#x2F; stable main&lt;&#x2F;code&gt; ลงในบรรทัดสุดท้ายของไฟล์นี้ &lt;code&gt;&#x2F;etc&#x2F;apt&#x2F;source.list&lt;&#x2F;code&gt; สามารถทำได้โดยคำสั่งด้านล่างนี้ หรือวิธีอื่นๆ ตามที่ถนัดเลย&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo echo &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;deb http:&#x2F;&#x2F;dl.google.com&#x2F;linux&#x2F;chrome&#x2F;deb&#x2F; stable main&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt; &#x2F;etc&#x2F;apt&#x2F;source.list&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo aptitude update&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;หมายเหตุ:&lt;&#x2F;strong&gt; ที่ต้องใช้คำสั่ง &lt;code&gt;sudo aptitude update&lt;&#x2F;code&gt; หลังจากการเพิ่ม URL ของ repository ในไฟล์ &lt;code&gt;&#x2F;etc&#x2F;apt&#x2F;source.list&lt;&#x2F;code&gt; แล้วเพราะว่า คำสั่ง &lt;code&gt;aptitude update&lt;&#x2F;code&gt; เป็น คำสั่งที่โหลดรายการซอฟแวร์ที่ใหม่ล่าสุดลงมาสำรองไว้บนเครื่องเรา เพื่อที่จะสามารถค้นหาและติดตั้งซอฟแวร์ได้ จึงทำให้เมื่อเพิ่ม &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;dl.google.com&#x2F;linux&#x2F;chrome&#x2F;deb&#x2F;&quot;&gt;repository ของ Google Chrome&lt;&#x2F;a&gt; ลงไปแล้ว รายการซอฟแวร์ที่ใหม่ที่อัพเดทล่าสุดจะมี ซอฟแวร์ Google Chrome ปรากฏเพิ่มมาด้วย เราสามารถใช้คำสั่ง &lt;code&gt;$ sudo aptitude search google-chrome&lt;&#x2F;code&gt; ถ้าดำเนินการเสร็จแล้วจะขึ้นรายการซอฟแวร์มาเลือกให้เราติืดตั้ง&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;แต่ถ้าเกิดข้อผิดพลาดแบบนี้ หรือคล้ายๆ กับแบบนี้&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;W: GPG error: http:&#x2F;&#x2F;dl.google.com stable Release: The following signatures couldn&amp;#39;t be verified because the public key is not available: NO_PUBKEY A040830F7FAC5991
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;มันหมายความว่า กุญแจ public key ของคุณนั้น (ในกรณี &lt;code&gt;A040830F7FAC5991&lt;&#x2F;code&gt; คือ public key ของผม) ไม่สามารถที่จะยืนยันได้&lt;&#x2F;p&gt;
&lt;h3 id=&quot;withiiaek&quot;&gt;วิธีแก้&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiiaek&quot; aria-label=&quot;Anchor link for: withiiaek&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ให้ใช้คำสั่งต่อไปนี้ในการรับรอง repository จาก Google โดยที่ &lt;code&gt;[Your public KEY]&lt;&#x2F;code&gt; ให้ใส่ public key ของคุณ&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo apt-key adv&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;keyserver&lt;&#x2F;span&gt; keyserver.ubuntu.com&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;recv-keys&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;Your public KEY&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;โอเค ได้เวลาลง Google Chrome จริงๆล่ะ&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ sudo aptitude update
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ sudo aptitude install google-chrome-stable
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;หมายเหตุ:&lt;&#x2F;strong&gt;: Google Chrome มีทั้งหมด 3 รุ่น คือ &lt;code&gt;google-chrome-beta&lt;&#x2F;code&gt;, &lt;code&gt;google-chrome-stable&lt;&#x2F;code&gt; และ &lt;code&gt;google-chrome-unstable&lt;&#x2F;code&gt; ก็คือ รุ่นทดลองใช้งาน(beta), รุ่นเสถียรแล้ว(stable) และ รุ่นไม่เสถียร(unstable) ตามลำดับ โดย รุ่นทดลองใช้งานกับรุ่นไม่เสถียร อาจจะมีบัค(ข้อผิดพลาด)บ้าง โดยเฉพาะในรุ่นไม่เสถียรจะมีมากสุด แต่ในขณะเดีัยวกันจะได้ความสามารถที่ใหม่กว่า ขึ้นอยู่กับความต้องการเลย เนื่องจากผมต้องใช้งานบ่อยเลยเลือกรุ่นเสถียรแทน (&lt;code&gt;google-chrome-stable&lt;&#x2F;code&gt;)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>How to Install Google Chrome on Debian</title>
		<published>2015-06-22T00:00:00+00:00</published>
		<updated>2015-06-22T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/how-to-install-google-chrome-on-debian/" type="text/html"/>
		<id>https://thadaw.com/posts/how-to-install-google-chrome-on-debian/</id>
		<content type="html">&lt;h1 id=&quot;deprecated-post&quot;&gt;*Deprecated post!&lt;a class=&quot;zola-anchor&quot; href=&quot;#deprecated-post&quot; aria-label=&quot;Anchor link for: deprecated-post&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;Please go to &lt;a href=&quot;&#x2F;a-very-short-ubuntu-debian-packages-installation-sheet-0967oym&#x2F;&quot;&gt;my new post&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;prerequisite&quot;&gt;Prerequisite&lt;a class=&quot;zola-anchor&quot; href=&quot;#prerequisite&quot; aria-label=&quot;Anchor link for: prerequisite&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;chromium via &lt;code&gt;$ sudo aptitude install chromium&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;a class=&quot;zola-anchor&quot; href=&quot;#installation&quot; aria-label=&quot;Anchor link for: installation&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add Google Chrome repository from &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;wiki.debian.org&#x2F;UnofficialRepositories&quot;&gt;unofficial debian repository&lt;&#x2F;a&gt; by add &lt;code&gt;deb http:&#x2F;&#x2F;dl.google.com&#x2F;linux&#x2F;chrome&#x2F;deb&#x2F; stable main&lt;&#x2F;code&gt; into last line of &lt;code&gt;&#x2F;etc&#x2F;apt&#x2F;source.list&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo echo &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;deb http:&#x2F;&#x2F;dl.google.com&#x2F;linux&#x2F;chrome&#x2F;deb&#x2F; stable main&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt; &#x2F;etc&#x2F;apt&#x2F;source.list&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo aptitude update&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;If you got the error look like this&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;W: GPG error: http:&#x2F;&#x2F;dl.google.com stable Release: The following signatures couldn&amp;#39;t be verified because the public key is not available: NO_PUBKEY A040830F7FAC5991
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It means your public key (In my case, (&lt;code&gt;A040830F7FAC5991&lt;&#x2F;code&gt; is my public key) can&#x27;t verify. Use the belowing command to sign &amp;amp; trust the new repository from google. using &lt;code&gt; $ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys [Your public KEY]&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;example&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A040830F7FAC5991
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;It&#x27;s time to Install Google Chrome!&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ sudo aptitude update
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ sudo aptitude install google-chrome-stable
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Google Chrome has 3 version: &lt;code&gt;google-chrome-beta&lt;&#x2F;code&gt;, &lt;code&gt;google-chrome-stable&lt;&#x2F;code&gt; and &lt;code&gt;google-chrome-unstable&lt;&#x2F;code&gt;. My case uses &lt;code&gt;google-chrome-stable&lt;&#x2F;code&gt; for daily use.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>GitHub Page Build Failure Solution</title>
		<published>2015-06-20T00:00:00+00:00</published>
		<updated>2015-06-20T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/error-github-page-build-failure/" type="text/html"/>
		<id>https://thadaw.com/posts/error-github-page-build-failure/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; This is a part of solutions for solving belowing problem message from GitHub Page. It may be other solutions for solving the problem.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;situation&quot;&gt;Situation&lt;a class=&quot;zola-anchor&quot; href=&quot;#situation&quot; aria-label=&quot;Anchor link for: situation&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;My jekyll page can run locally.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I got an email &quot;[mildronize.github.io] Page build failure&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I asked supportor that the facing problem&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I don&#x27;t understand why my file contains syntax errors. Because I can run normally this file in local (using jekyll serve)
Can you show me more information about this errors or suggest anything.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;He responded me&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;You should be running your site locally exactly as per these instructions:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;help.github.com&#x2F;articles&#x2F;using-jekyll-with-pages&quot;&gt;https:&#x2F;&#x2F;help.github.com&#x2F;articles&#x2F;using-jekyll-with-pages&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I cloned your repository and reproduced the issue locally by using a Gemfile and running:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;bundle exec jekyll build&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Which produced the error details:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;Conversion error: Jekyll::Converters::Markdown encountered an error converting &#x27;_posts&#x2F;2015-06-08-upgrade-debian-to-sid.md&#x27;.&lt;&#x2F;code&gt;
...&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;ClassNotFound(&#x27;no lexer for alias %r found&#x27; % _alias) ClassNotFound: no lexer for alias &#x27;shell&#x27; found&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;solution&quot;&gt;solution&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution&quot; aria-label=&quot;Anchor link for: solution&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;You can&#x27;t use &lt;code&gt;shell&lt;&#x2F;code&gt; as a lexer name. Try &lt;code&gt;bash&lt;&#x2F;code&gt; instead.
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jekyll&#x2F;jekyll&#x2F;issues&#x2F;1183&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;jekyll&#x2F;jekyll&#x2F;issues&#x2F;1183&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you have any question or suggestion, don&#x27;t forget to comment this post. Thank you.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>มาอัพเดท Debian จากเวอร์ชั่น stable มาเป็น sid กันเถอะ</title>
		<published>2015-06-08T00:00:00+00:00</published>
		<updated>2015-06-08T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/upgrade-debian-to-sid-th/" type="text/html"/>
		<id>https://thadaw.com/posts/upgrade-debian-to-sid-th/</id>
		<content type="html">&lt;p&gt;โดยปกติแล้ว เวลาลง Debian ใหม่ๆ จะไม่สามารถใช้ คำสั่ง sudo ได้ ไม่เหมือนกับ Ubuntu ที่ตอนติดตั้งจะให้ user แรกที่สร้างตอนติดตั้งสามารถใช้ คำสั่ง sudo ได้เลย&lt;&#x2F;p&gt;
&lt;p&gt;ดังนั้น เพื่อให้ user ของเราเองมีสิทธิเทียบเท่าผู้ดูแลระบบ(system administrators ) เราจึงต้องลง package ชื่อว่า sudo และใช้สิทธิผู้ดูแลระบบอนุญาตให้ user ของเรามีสิทธิเทียบเท่าผู้ดูแลระบบ เพราะในบางคำสั่งจำเป็นต้องใช้สิทธิ ผู้ดูแลระบบในการทำงาน เช่น การติดตั้ง โปรแกรม (หรือ package) โดยใช้คำสั่งด้านล่างนี้&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; su&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; aptitude install sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; usermod -a -G sudo [USERNAME]&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;wiki.debian.org&#x2F;sudo&quot;&gt;sudo&lt;&#x2F;a&gt; คือ คำสั่งที่ให้ ผู้ดูแลระบบ อนุญาตให้่บาง user สามารถใช้คำสั่งที่ได้สิทธิเทียบเท่าผู้ดูแลระบบได้&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;khant-n&quot;&gt;ขั้นตอน&lt;a class=&quot;zola-anchor&quot; href=&quot;#khant-n&quot; aria-label=&quot;Anchor link for: khant-n&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;ให้คัดลอกข้อความด้านล่างนี้แทนที่ ของเดิมไปเลย โดยไปไว้ที่ &lt;code&gt;&#x2F;etc&#x2F;apt&#x2F;sorces.list&lt;&#x2F;code&gt; กับโปรแกรมแก้ไขข้อความตัวไหนก็ได้ที่คุณชอบ โดยในที่นี้ผมจะใช้ vi โดยใช้ &lt;code&gt;$ sudo vi &#x2F;etc&#x2F;apt&#x2F;sources.list&lt;&#x2F;code&gt; และคัดลอกข้อมูลด้านล่างลงไปแล้วก็บันทึก&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;deb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; http:&#x2F;&#x2F;ftp.th.debian.org&#x2F;debian&#x2F; sid main contrib non-free&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;deb-src&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; http:&#x2F;&#x2F;ftp.th.debian.org&#x2F;debian&#x2F; sid main contrib non-free&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;deb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; http:&#x2F;&#x2F;ftp.th.debian.org&#x2F;debian&#x2F; stable main contrib non-free&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;deb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; http:&#x2F;&#x2F;ftp.th.debian.org&#x2F;debian&#x2F; testing main contrib non-free&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;deb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; http:&#x2F;&#x2F;ftp.th.debian.org&#x2F;debian&#x2F; experimental main contrib non-free&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Read more about Archive areas:
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;doc&#x2F;debian-policy&#x2F;ch-archive.html#s-main&quot;&gt;main&lt;&#x2F;a&gt;,
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;doc&#x2F;debian-policy&#x2F;ch-archive.html#s-contrib&quot;&gt;contrib&lt;&#x2F;a&gt;,
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;doc&#x2F;debian-policy&#x2F;ch-archive.html#s-non-free&quot;&gt;non-free&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Replace &lt;code&gt;http:&#x2F;&#x2F;ftp.th.debian.org&#x2F;debian&#x2F;&lt;&#x2F;code&gt; to your nearest repository&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ทำการอัพเดทรายการ package ทั้งหมดที่อยู่ใน repository ที่เราใส่ไว้ในข้อที่ 1&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo aptitude update&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;จากนั้นทำการอัพเกรดระบบ Debain ไปยัง sid (หรือ unstable)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo aptitude dist-upgrade&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;เมื่อเสร็จสิ้น สั่งรีบูตเครื่อง&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo reboot&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;ephimetim-cchalngkaidaimlngkaid&quot;&gt;เพิ่มเติม จะลงก็ได้ไม่ลงก็ได้:&lt;a class=&quot;zola-anchor&quot; href=&quot;#ephimetim-cchalngkaidaimlngkaid&quot; aria-label=&quot;Anchor link for: ephimetim-cchalngkaidaimlngkaid&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;การลง firmware บางตัวที่มี &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;doc&#x2F;debian-policy&#x2F;ch-archive.html#s-non-free&quot;&gt;non-free&lt;&#x2F;a&gt; อยู่ด้วยเช่น drivers เพื่อให้สามารถใช้ driver บางอันได้&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;สรุปคือลงๆ ไปเถอะ คือบาง driver เช่น &lt;code&gt;driver การ์ดจอ&lt;&#x2F;code&gt; มันไม่ใช่ open source แต่เราสามารถใช้งานได้ฟรี ดังนั้นลงๆ ตัวนี้ไปเถอะ จะได้มี driver ใช้&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ sudo aptitude install firmware-linux
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ถ้าลง Debian ใหม่้ๆ แล้วจะไม่มีภาษาไทยมาให้ ตัวอักษรจะเป็นภาษาที่อ่านไม่ออก ดังนั้นควรจะลง &lt;code&gt;xfonts-thai&lt;&#x2F;code&gt; ด้วย จะได้อ่านภาษาไทยได้ สรุปคือลงๆ ไปเถอะถ้าเป็นคนไทย&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ sudo aptitude install xfonts-thai
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>How to upgrade Debian to SID</title>
		<published>2015-06-08T00:00:00+00:00</published>
		<updated>2015-06-08T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/upgrade-debian-to-sid/" type="text/html"/>
		<id>https://thadaw.com/posts/upgrade-debian-to-sid/</id>
		<content type="html">&lt;p&gt;&lt;strong&gt;Optional:&lt;&#x2F;strong&gt; Add &lt;code&gt;sudo&lt;&#x2F;code&gt; into your user&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ su
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# aptitude install sudo
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# usermod -a -G sudo [USERNAME]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# exit
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: If &lt;code&gt;sudo&lt;&#x2F;code&gt; don&#x27;t work, try logout and login again.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Replace the belowing text into &lt;code&gt;&#x2F;etc&#x2F;apt&#x2F;sources.list&lt;&#x2F;code&gt; with your favorite editor. In my case I use
&lt;code&gt;$ sudo vi &#x2F;etc&#x2F;apt&#x2F;sources.list&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;deb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; http:&#x2F;&#x2F;ftp.th.debian.org&#x2F;debian&#x2F; sid main contrib non-free&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;deb-src&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; http:&#x2F;&#x2F;ftp.th.debian.org&#x2F;debian&#x2F; sid main contrib non-free&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;deb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; http:&#x2F;&#x2F;ftp.th.debian.org&#x2F;debian&#x2F; stable main contrib non-free&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;deb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; http:&#x2F;&#x2F;ftp.th.debian.org&#x2F;debian&#x2F; testing main contrib non-free&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;deb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; http:&#x2F;&#x2F;ftp.th.debian.org&#x2F;debian&#x2F; experimental main contrib non-free&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Read more about Archive areas:
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;doc&#x2F;debian-policy&#x2F;ch-archive.html#s-main&quot;&gt;main&lt;&#x2F;a&gt;,
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;doc&#x2F;debian-policy&#x2F;ch-archive.html#s-contrib&quot;&gt;contrib&lt;&#x2F;a&gt;,
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;doc&#x2F;debian-policy&#x2F;ch-archive.html#s-non-free&quot;&gt;non-free&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Replace &lt;code&gt;http:&#x2F;&#x2F;ftp.th.debian.org&#x2F;debian&#x2F;&lt;&#x2F;code&gt; to your nearest repository&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Update a list of repositories&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo aptitude update&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Upgrade your debian version into sid version&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo aptitude dist-upgrade&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;After it finished, reboot system&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sudo reboot&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;Optional:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For installing firmware for various drivers in consist of &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;doc&#x2F;debian-policy&#x2F;ch-archive.html#s-non-free&quot;&gt;non-free&lt;&#x2F;a&gt; packages or drivers using:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ sudo aptitude install firmware-linux
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;For installing some thai font:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ sudo aptitude install xfonts-thai
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>การแทนตัวอักษรภาษาไทยในระบบการเข้ารหัสแบบต่างๆ</title>
		<published>2015-05-24T00:00:00+00:00</published>
		<updated>2015-05-24T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/thai-encoding-th/" type="text/html"/>
		<id>https://thadaw.com/posts/thai-encoding-th/</id>
		<content type="html">&lt;h2 id=&quot;ascii&quot;&gt;ASCII&lt;a class=&quot;zola-anchor&quot; href=&quot;#ascii&quot; aria-label=&quot;Anchor link for: ascii&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ในระบบการแสดงผลแบบเก่า ตัวอักษรในภาษาอังกฤษนั้นจะจัดเก็บอยู่ในลักษณะของ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;ASCII&quot;&gt;ASCII&lt;&#x2F;a&gt; จะจัดเก็บตัวอักษรต่างๆ อยู่ในช่วง 0-127 (หรือ 7 bit หรือก็คือจะต้องใช้ข้อมูเลขฐานสอง 7 ตัว) ในการแทนการแสดงผลตัวอักษรภาษาอังกฤษหนึ่งตัว โดย 7 bit สามารถแทนข้อมูลต่างๆ ได้ ตั้งแต่ A-Z, a-z, ตัวเลข 0-9 และเครื่องหมาย รวมถึงตัวอักษรพิเศษต่างๆ และตัวอักษรที่มองไม่เห็น (&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Whitespace_character&quot;&gt;Whitespace character&lt;&#x2F;a&gt;) และ เช่น ตัวอักษรเอพิมพ์ใหญ่ (A) นั้นมี ASCII คือ 65 หรือ 1000001 ในเลขฐานสอง เป็นต้น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.ascii-code.com&#x2F;&quot;&gt;สามารถดูตาราง ASCII ทั้งหมดได้ที่่&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;การแสดงผลภาษาอื่นๆ บนการเข้ารหัส(encode) แบบ ASCII นั้นทำได้ แต่จะขึ้นอยู่กับระบบปฏิบัติการ(OS) และใช้ในวงแคบ โดยเป็นการขยายความสามารถของ ASCII โดยเพิ่มอีก 1 bit รวมเป็น 8 bit คืออยู่ในช่วง 128-255 ที่ใช้แทนตัวอักษรเพียงได้แค่หนึ่งภาษา ในภาษาไทยมีการใช้วิธีการเข้ารหัสที่หลากหลาย ที่ต่อยอดจากระบบ ASCII เดิม เช่น ใน Windows จะใช้การเข้ารหัสแบบ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;msdn.microsoft.com&#x2F;en-us&#x2F;goglobal&#x2F;cc305142.aspx&quot;&gt;Windows 874&lt;&#x2F;a&gt; ซึ่งใช้ได้เฉพาะ Windows เท่านั้น หรือการเข้ารหัสแบบ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.nectec.or.th&#x2F;it-standards&#x2F;std620&#x2F;std620.htm&quot;&gt;TIS-620&lt;&#x2F;a&gt; ที่ใช้ในวงแคบ ถ้าไม่ได้มีการติดตั้งเครื่องมือสำหรับการอ่าน TIS-620 ไว้ เช่น การเข้าเว็บภาษาไทยจากคอมพิวเตอร์ต่างประเทศ ก็จะทำให้ไม่สามารถแสดงผลภาษาไทยได้ถูกต้อง&lt;&#x2F;p&gt;
&lt;h2 id=&quot;unicode&quot;&gt;Unicode&lt;a class=&quot;zola-anchor&quot; href=&quot;#unicode&quot; aria-label=&quot;Anchor link for: unicode&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;และเพื่อการใช้งานเป็นสากล ไม่ขึ้นอยู่กับระบบปฏิบัติการ(OS) จึงมีการคิดค้น &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.unicode.org&#x2F;standard&#x2F;WhatIsUnicode.html&quot;&gt;Unicode&lt;&#x2F;a&gt; ซึ่ง Unicode คือการแทนตัวอักษรทุกๆ ตัวอักษร โดยไม่ขึ้นต่อระบบปฏิบัติการ โปรแกรมและ ภาษา โดย Unicode นั้น จะมีการแทน 1 ตัวอักษรของแต่ละภาษาด้วยหลายๆ ไบต์ (Multi-byte encodings) จึงทำให้ใช้พื้นที่ในการจัดเก็บเยอะกว่า แต่สามารถใช้งานได้สะดวก และรองรับทุกๆ ภาษา โดยปกติแล้วการ ส่งข้อมูลหรือการแสดงผ่านเว็บนั้น จะใช้การเข้ารหัสแบบ UTF-8 เพื่อความเป็นสากล ใช้งานได้ทุกภาษา (ซึ่ง UTF-8 จัดเป็น Unicode เลข 8 หมายถึงจำนวนบิตที่ใช้ในการแทนตัวอักษร) ส่วนบน Windows จะใช้ UTF-16 แต่ถ้าบนตระกูล Linux จะใช้ UTF-8&lt;&#x2F;p&gt;
&lt;h2 id=&quot;srup&quot;&gt;สรุป&lt;a class=&quot;zola-anchor&quot; href=&quot;#srup&quot; aria-label=&quot;Anchor link for: srup&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;เพื่อการใช้งานภาษาไทย และรองรับภาษาทุกๆ ภาษาแล้ว ดังนั้นเราควรที่จะเลือกใช้งานวิธีการเข้ารหัสแบบ Unicode ซึ่งจะเป็น UTF-8 หรือแบบ อื่นๆ ขึ้นอยู่กับการใช้งาน โดยเฉพาะการใช้การเข้ารหัสภาษาไทยบนเว็บนั้น ควรจะเปลี่ยนมาใข้ Unicode แทนแบบ TIS-620 และ Windows-874&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aanephimetim&quot;&gt;อ่านเพิ่มเติม&lt;a class=&quot;zola-anchor&quot; href=&quot;#aanephimetim&quot; aria-label=&quot;Anchor link for: aanephimetim&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;643810&quot;&gt;ความแตกต่างระหว่าง UTF-8 และ Unicode รวมถึงการกล่าวถึงประวัติความเป็นมาของวิธีการเข้ารหัสในแบบต่างๆ &lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;unicode-table.com&#x2F;th&#x2F;&quot;&gt;ตาราง Unicode ภาษาไทย&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.ascii-code.com&#x2F;&quot;&gt;ตาราง ASCII&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.nectec.or.th&#x2F;it-standards&#x2F;std620&#x2F;std620.htm&quot;&gt;มาตรฐานการเข้ารหัส TIS-620&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>ปัญหาการพิมพ์ภาษาไทยบน Atom Editor</title>
		<published>2015-05-23T00:00:00+00:00</published>
		<updated>2015-05-23T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/thai-typing-in-atom-editor-th/" type="text/html"/>
		<id>https://thadaw.com/posts/thai-typing-in-atom-editor-th/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;อัพเดท 2015-07-05: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.blognone.com&#x2F;node&#x2F;69792&quot;&gt;Atom Editor ออกรุ่น 1.0 แล้ว&lt;&#x2F;a&gt; ผมได้ทดสอบแล้วแต่ก็ยังไม่สามารถใช้งานภาษาไทยได้&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;หมายเหตุ: ถ้าใครยังไม่รู้จัก Atom Editor ลองอ่าน&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.blognone.com&#x2F;node&#x2F;56176&quot;&gt;บทความรีวิวจาก Blognone ดูนะครับ&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;payhaathiiphb&quot;&gt;ปัญหาที่พบ&lt;a class=&quot;zola-anchor&quot; href=&quot;#payhaathiiphb&quot; aria-label=&quot;Anchor link for: payhaathiiphb&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ปัญหาที่ผมพบในการพิมพ์ภาษาไทยบน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;atom.io&quot;&gt;Atom Editor&lt;&#x2F;a&gt; คือ cursor ที่แสดงผลขณะกำลังพิมพ์นั้นไม่ตรงกับ สิ่งที่แสดงผลจริงๆ&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;thai-typing-in-atom-editor-th&#x2F;2015-05-23-thai-typing-in-atom-editor.gif&quot; alt=&quot;Problem while typing Thai in Atom editor&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;หลังจากผมได้พบกับปัญหานี้ผมได้ ไปค้นหาปัญหานี้ใน google ผลปรากฏว่าได้มีคนที่ประสบปัญหาแบบเดียวกันกับผม ซึ่งตอนนี้ได้มีคนไปตั้งประเด็นนี้ไว้ใน Github ของ Atom Editor แล้ว ใน &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;atom&#x2F;atom&#x2F;issues&#x2F;1849&quot;&gt;Some unicode characters seem to confuse Atom #1849&lt;&#x2F;a&gt; ตั้งแต่ปี 2557 ซึ่งตอนนี้ (ณ วันที่เขียนบทความนี้) ยังไม่ได้แก้ไขปัญหานี้ได้&lt;&#x2F;p&gt;
&lt;h2 id=&quot;laksnakh-ngpayhaa&quot;&gt;ลักษณะของปัญหา&lt;a class=&quot;zola-anchor&quot; href=&quot;#laksnakh-ngpayhaa&quot; aria-label=&quot;Anchor link for: laksnakh-ngpayhaa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;โดยภาษาไทยเป็นการเข้ารหัส เพื่อการแสดงผลแบบ Unicode ซึ่งจะใช้ข้อมูลหลายๆ byte ในการแทนตัวอักษรภาษาไทยหนึ่งตัว และด้วยเหตุนี้ Atom editor ไม่สามารถแยกแยะได้ว่าตัวอักษรภาษาไทยแต่ละตัวนั้น สิ้นสุดที่อักขระ(byte) ตัวไหนจึงทำให้การแสดงผลตำแหน่ง cursor มีการผิดพลาดเกิดขึ้น&lt;&#x2F;p&gt;
&lt;p&gt;เพื่อความเข้าใจมากยิ่งขึ้น สามารถอ่านคำอธิบาย [การแทนตัวอักษรภาษาไทยในระบบการเข้ารหัสแบบต่างๆ] เพิ่มเติมได้&lt;&#x2F;p&gt;
&lt;h2 id=&quot;withiikaaraekaikhpayhaaebuue-ngtn&quot;&gt;วิธีการแก้ไขปัญหาเบื้องต้น&lt;a class=&quot;zola-anchor&quot; href=&quot;#withiikaaraekaikhpayhaaebuue-ngtn&quot; aria-label=&quot;Anchor link for: withiikaaraekaikhpayhaaebuue-ngtn&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;หลังจากผมได้ทดสอบเปลี่ยนฟอนต์ภาษาไทยหลายๆ ฟอนต์ ใน Atom Editor บน Windows 8.1 พบว่า ฟอนต์ Umpush มีปัญหาน้อยที่สุด ซึ่งเท่าที่ผมพบ มีปัญหาแค่ตัวอักษร &quot;สระอำ&quot; แค่ตัวเดียว&lt;&#x2F;p&gt;
&lt;p&gt;ถ้าใครมีวิธีการแก้ปัญหาที่ดีกว่านี้ ก็สามารถนำมาแบ่งปันได้นะครับ&lt;&#x2F;p&gt;
&lt;p&gt;ซึ่งตอนนี้ใน Atom Editor ผมได้ตั้งค่าฟอนต์ใน ไฟล์ &lt;code&gt;config.cson&lt;&#x2F;code&gt; ซึ่งอยู่ใน root ของ setting ของ Atom ดังนี้&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;fontFamily: &quot;Inconsolata, Umpush, Arial, sans-serif&quot;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;หรือสามารถตั้งค่าผ่าน GUI ของ Atom Editor ได้ ที่ File &amp;gt; Settings &amp;gt; Editor Settings (หัวข้อ)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;thai-typing-in-atom-editor-th&#x2F;2015-05-23-thai-typing-in-atom-editor-2.jpg&quot; alt=&quot;config of Atom to solve such problem&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kham-thibaay&quot;&gt;คำอธิบาย&lt;a class=&quot;zola-anchor&quot; href=&quot;#kham-thibaay&quot; aria-label=&quot;Anchor link for: kham-thibaay&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;ใช้ฟอนต์ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;levien.com&#x2F;type&#x2F;myfonts&#x2F;inconsolata.html&quot;&gt;Inconsolata&lt;&#x2F;a&gt; เป็นฟอนต์ ภาษาอังกฤษหลักๆ&lt;&#x2F;li&gt;
&lt;li&gt;ใช้ฟอนต์ &lt;a href=&quot;ftp:&#x2F;&#x2F;linux.thai.net&#x2F;pub&#x2F;thailinux&#x2F;software&#x2F;thai-ttf&quot;&gt;Umpush&lt;&#x2F;a&gt; สำหรับการแสดงผลภาษาไทย (&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;linux.thai.net&#x2F;projects&#x2F;thaifonts-scalable&quot;&gt;หน้าแรก&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;หรือเอาง่ายๆ เปลี่ยน Editor ไปเลย เปลี่ยนไปใช้ &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;brackets.io&#x2F;&quot;&gt;Brackets&lt;&#x2F;a&gt; แทน ไม่มีปัญหาเรื่องการพิมพ์ภาษาไทยแน่ๆ  เดี๋ยวในอนาคตผมอาจจะมารีวิวโปรแกรม Brackets กันครับ&lt;&#x2F;p&gt;
&lt;h2 id=&quot;khamthiiekiiywkh-ng&quot;&gt;คำที่เกี่ยวข้อง&lt;a class=&quot;zola-anchor&quot; href=&quot;#khamthiiekiiywkh-ng&quot; aria-label=&quot;Anchor link for: khamthiiekiiywkh-ng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;atom&#x2F;atom&#x2F;issues&#x2F;6413&quot;&gt;Error when I put my cursor to the text&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;atom&#x2F;atom&#x2F;issues&#x2F;3498&quot;&gt;Cursor positioning on certain Unicode characters&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;atom&#x2F;atom&#x2F;issues&#x2F;5975&quot;&gt;incorrect cursor placement on lines with accented characters&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;atom&#x2F;atom&#x2F;issues&#x2F;4595&quot;&gt;wrong cursor location with multi-byte characters&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Responsive expanding search bar</title>
		<published>2015-05-07T00:00:00+00:00</published>
		<updated>2015-05-07T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/responsive-expanding-search-bar/" type="text/html"/>
		<id>https://thadaw.com/posts/responsive-expanding-search-bar/</id>
		<content type="html">&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;responsive-expanding-search-bar&#x2F;2015-05-06-responsive-expanding-search-bar.jpg&quot; alt=&quot;responsive-expanding-search-bar&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;!-- demo: &#x2F;demo&#x2F;responsive-expanding-search-bar&#x2F; --&gt;
&lt;p&gt;&lt;strong&gt;Expanding Search Bar&lt;&#x2F;strong&gt; is an expanding search bar extension for any HTML page or Jekyll. This extension is a lightweight version of &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;tympanus.net&#x2F;Tutorials&#x2F;ExpandingSearchBar&#x2F;&quot;&gt;Expanding Search Bar Deconstructed&lt;&#x2F;a&gt; for using  in Jekyll or HTML. This extension is used in &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;mildronize.github.io&quot;&gt;my blog&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Because &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;mildronize.github.io&quot;&gt;my blog&lt;&#x2F;a&gt; have used icon set from &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;fontawesome.io&quot;&gt;Font Awesome&lt;&#x2F;a&gt;. I change icon set from the &lt;a href=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;responsive-expanding-search-bar&#x2F;#original-project-documentation&quot;&gt;original project&lt;&#x2F;a&gt; into &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;fontawesome.io&quot;&gt;Font Awesome&lt;&#x2F;a&gt; as in &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;mildronize.github.io&quot;&gt;my blog&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;a class=&quot;zola-anchor&quot; href=&quot;#usage&quot; aria-label=&quot;Anchor link for: usage&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;copy all of project&#x27;s resource to your project.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;css
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;fonts
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;js
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Insert css header into your HTML&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;html&quot; class=&quot;language-html z-code&quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-tag z-inline z-any z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-inline z-any z-html&quot;&gt;link&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;rel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;stylesheet&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;text&#x2F;css&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;href&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;css&#x2F;font-awesome-4.3.0.min.css&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-tag z-inline z-any z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-inline z-any z-html&quot;&gt;link&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;rel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;stylesheet&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;text&#x2F;css&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;href&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;css&#x2F;expanding-search-bar.css&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Place below code into top of HTML code or anywhere what you want.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;html&quot; class=&quot;language-html z-code&quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-tag z-block z-any z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-block z-any z-html&quot;&gt;div&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-id z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-id z-html&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-meta z-toc-list z-id z-html&quot;&gt;sb-search&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-class z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-class z-html&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-meta z-class-name z-html&quot;&gt;sb-search&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;  &lt;span class=&quot;z-meta z-tag z-block z-form z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-block z-form z-html&quot;&gt;form&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;      &lt;span class=&quot;z-meta z-tag z-inline z-form z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-inline z-form z-html&quot;&gt;input&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-class z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-class z-html&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-meta z-class-name z-html&quot;&gt;sb-search-input&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-class-name z-html&quot;&gt;search-bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;placeholder&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Enter your search term...&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;text&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;search&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-id z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-id z-html&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-meta z-toc-list z-id z-html&quot;&gt;search&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;      &lt;span class=&quot;z-meta z-tag z-inline z-form z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-inline z-form z-html&quot;&gt;input&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-class z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-class z-html&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-meta z-class-name z-html&quot;&gt;sb-search-submit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;submit&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;      &lt;span class=&quot;z-meta z-tag z-inline z-any z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-inline z-any z-html&quot;&gt;span&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-class z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-class z-html&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-meta z-class-name z-html&quot;&gt;fa&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-class-name z-html&quot;&gt;fa-search&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-class-name z-html&quot;&gt;sb-icon-search&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-inline z-any z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-inline z-any z-html&quot;&gt;span&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;  &lt;span class=&quot;z-meta z-tag z-block z-form z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-block z-form z-html&quot;&gt;form&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-tag z-block z-any z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-block z-any z-html&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Add JS at bottom of HTML code&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;html&quot; class=&quot;language-html z-code&quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;js&#x2F;classie.js&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-end z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;js&#x2F;uisearch.js&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-end z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-begin z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;  &lt;span class=&quot;z-source z-js z-embedded z-html&quot;&gt;&lt;span class=&quot;z-source z-js&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-word z-new z-js&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-constructor z-js&quot;&gt; &lt;span class=&quot;z-variable z-type z-js&quot;&gt;UISearch&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-js&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-js&quot;&gt;(&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-method z-js&quot;&gt;&lt;span class=&quot;z-support z-type z-object z-dom z-js&quot;&gt;document&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-js&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-js&quot;&gt;getElementById&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-js&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-js&quot;&gt;(&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-js&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-js&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-js&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;sb-search&lt;span class=&quot;z-punctuation z-definition z-string z-end z-js&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-group z-end z-js&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-js&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-js&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-source z-js z-embedded z-html&quot;&gt;&lt;span class=&quot;z-source z-js&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-script z-end z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-script z-html&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;source&quot;&gt;Source&lt;a class=&quot;zola-anchor&quot; href=&quot;#source&quot; aria-label=&quot;Anchor link for: source&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;ExpandingSearchBar&quot;&gt;Github&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;ExpandingSearchBar&#x2F;archive&#x2F;master.zip&quot;&gt;Download&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;original-project-documentation&quot;&gt;Original project documentation&lt;a class=&quot;zola-anchor&quot; href=&quot;#original-project-documentation&quot; aria-label=&quot;Anchor link for: original-project-documentation&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;A tutorial on how to create a mobile-friendly and responsive expanding search bar.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;tympanus.net&#x2F;codrops&#x2F;?p=15599&quot;&gt;article on Codrops&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;tympanus.net&#x2F;Tutorials&#x2F;ExpandingSearchBar&#x2F;&quot;&gt;demo&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;tympanus.net&#x2F;codrops&#x2F;licensing&#x2F;&quot;&gt;LICENSING &amp;amp; TERMS OF USE&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>My blog development for Jekyll site</title>
		<published>2015-05-06T00:00:00+00:00</published>
		<updated>2015-05-06T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/my-blog-development/" type="text/html"/>
		<id>https://thadaw.com/posts/my-blog-development/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;This post is involving the old version site, built with &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;jekyllrb.com&quot;&gt;Jekyll&lt;&#x2F;a&gt;.
Demo site: https:&#x2F;&#x2F;jekyll.mildronize.com &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&quot;&gt;source&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;tools-for-v-2&quot;&gt;Tools for V.2&lt;a class=&quot;zola-anchor&quot; href=&quot;#tools-for-v-2&quot; aria-label=&quot;Anchor link for: tools-for-v-2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;main-tools&quot;&gt;Main Tools&lt;a class=&quot;zola-anchor&quot; href=&quot;#main-tools&quot; aria-label=&quot;Anchor link for: main-tools&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pages.github.com&quot;&gt;GitHub Page&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;jekyllrb.com&quot;&gt;Jekyll&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;travis-ci.org&#x2F;&quot;&gt;Travis&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.docker.com&#x2F;&quot;&gt;Docker&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;web-development-tools&quot;&gt;Web Development Tools&lt;a class=&quot;zola-anchor&quot; href=&quot;#web-development-tools&quot; aria-label=&quot;Anchor link for: web-development-tools&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;bulma.io&#x2F;&quot;&gt;Bulma&lt;&#x2F;a&gt; - CSS Framework&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;filamentgroup&#x2F;loadCSS&quot;&gt;loadCSS&lt;&#x2F;a&gt; - Load CSS files Asynchronously&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;&quot;&gt;React&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;webpack.js.org&#x2F;&quot;&gt;Webpack4&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;jquery.com&#x2F;&quot;&gt;JQuery&lt;&#x2F;a&gt; for using with table of contents&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;verlok&#x2F;lazyload&quot;&gt;lazyload&lt;&#x2F;a&gt; - Lazy load image&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;features&quot;&gt;Features&lt;a class=&quot;zola-anchor&quot; href=&quot;#features&quot; aria-label=&quot;Anchor link for: features&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Search Page with React&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;3d4vqbnd424wbsh&#x2F;2018-09-17-99-score-google-insight-web-optimization-6.jpg?raw=1&quot; alt=&quot;search&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Blurry Load like Medium. Thanks for &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;jmperezperez.com&#x2F;medium-image-progressive-loading-placeholder&#x2F;&quot;&gt;
José&#x27;s post&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;4t30cmbtezs3qbw&#x2F;2018-09-17-99-score-google-insight-web-optimization-7.gif?raw=1&quot; alt=&quot;image-load-blur&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Latest version is posted on
&lt;a href=&quot;&#x2F;posts&#x2F;2018-09-17-99-score-google-insight-web-optimization&#x2F;&quot;&gt;ได้ 99 คะแนนจาก Google Insights &amp;amp; เรียนรู้การทำ web optimization&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;tools-for-v-1&quot;&gt;Tools for V.1&lt;a class=&quot;zola-anchor&quot; href=&quot;#tools-for-v-1&quot; aria-label=&quot;Anchor link for: tools-for-v-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;main-tools-1&quot;&gt;Main Tools&lt;a class=&quot;zola-anchor&quot; href=&quot;#main-tools-1&quot; aria-label=&quot;Anchor link for: main-tools-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pages.github.com&quot;&gt;GitHub Page&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;jekyllrb.com&quot;&gt;Jekyll&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;hyde.getpoole.com&#x2F;&quot;&gt;Hyde&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.docker.com&#x2F;&quot;&gt;Docker&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;web-development-tools-1&quot;&gt;Web Development Tools&lt;a class=&quot;zola-anchor&quot; href=&quot;#web-development-tools-1&quot; aria-label=&quot;Anchor link for: web-development-tools-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;angularjs.org&#x2F;&quot;&gt;angularJS&lt;&#x2F;a&gt; for search page&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;ExpandingSearchBar&quot;&gt;My Expanding Search Bar&lt;&#x2F;a&gt;, that is original from &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;tympanus.net&#x2F;Tutorials&#x2F;ExpandingSearchBar&#x2F;&quot;&gt;Expanding Search Bar&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;fontawesome.io&quot;&gt;Font Awesome&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ghiculescu&#x2F;jekyll-table-of-contents&quot;&gt;Table of contents for Jekyll&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;jquery.com&#x2F;&quot;&gt;JQuery&lt;&#x2F;a&gt; for using with table of contents&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;structure&quot;&gt;Structure&lt;a class=&quot;zola-anchor&quot; href=&quot;#structure&quot; aria-label=&quot;Anchor link for: structure&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;blob&#x2F;master&#x2F;README.md&quot;&gt;see README.MD in this repository&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;timeline&quot;&gt;Timeline&lt;a class=&quot;zola-anchor&quot; href=&quot;#timeline&quot; aria-label=&quot;Anchor link for: timeline&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;01 Oct 2014 » Register &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pages.github.com&quot;&gt;GitHub Page&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;a48c4b03033496c16e1eeb6377f7a2fb6fa79586&quot;&gt;02 May 2015&lt;&#x2F;a&gt; » Clone &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;hyde.getpoole.com&#x2F;&quot;&gt;Hyde&lt;&#x2F;a&gt; theme&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;58f941a5a9d0066c5ea939aaab98f1adef291647&quot;&gt;03 May 2015&lt;&#x2F;a&gt; » Create a my &lt;a href=&quot;&#x2F;posts&#x2F;2015-05-03-how-to-setup-this-blog&quot;&gt;first post&lt;&#x2F;a&gt; and fill my profile&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;5b51c7691acb01beec8df5f3704f57d3da272922&quot;&gt;03 May 2015&lt;&#x2F;a&gt; » Add Note page&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;8f8d30957145551e13cec173019a8aeb19efe5e4&quot;&gt;04 May 2015&lt;&#x2F;a&gt; » Add social icons using &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;fontawesome.io&quot;&gt;Font Awesome&lt;&#x2F;a&gt; at sidebar&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;b4d40e52dae31f81b242ff689ad3fc0ae93f0b71&quot;&gt;04 May 2015&lt;&#x2F;a&gt; » Add &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.google.com&#x2F;analytics&#x2F;&quot;&gt;google analytics&lt;&#x2F;a&gt; at header&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;8604dd5504b7cd794da59923a36878b43df48cc3&quot;&gt;04 May 2015&lt;&#x2F;a&gt; » Add showcase layout&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;831f4fb466d0f9cd513a45c299b946ca2f398aed&quot;&gt;05 May 2015&lt;&#x2F;a&gt; » Add &lt;a href=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;my-blog-development&#x2F;%7B%7Bsite.baseurl%7D%7D&#x2F;search&#x2F;&quot;&gt;Search page&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;45272e4bb72d121d144827c6075a2a0bd48cd764&quot;&gt;05 May 2015&lt;&#x2F;a&gt; » Add search bar, and binding url and search bar on &lt;a href=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;my-blog-development&#x2F;%7B%7Bsite.baseurl%7D%7D&#x2F;search&#x2F;&quot;&gt;Search page&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;8f83e6963f2a70b0979ff4be8a85541a19e34594&quot;&gt;06 May 2015&lt;&#x2F;a&gt; » Add this note&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;ca7df4be719fd2b9891cbea53fce88722196f419&quot;&gt;06 May 2015&lt;&#x2F;a&gt; » &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;milanaryal.com&#x2F;2015&#x2F;adding-hover-anchor-links-to-header-on-github-pages-using-jekyll&quot;&gt;Add hover anchor links to header on GitHub Pages using Jekyll&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;7872d3039fd05e9b1b6f1581a13772b65c9c6b27&quot;&gt;06 May 2015&lt;&#x2F;a&gt; » Add html header for friendly with search engine such as keywords, description, etc.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;f8ff0a772521cf5b90cb0cd455bc9d8c85997ffb&quot;&gt;07 May 2015&lt;&#x2F;a&gt; » &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;help.disqus.com&#x2F;customer&#x2F;portal&#x2F;articles&#x2F;472138-jekyll-installation-instructions&quot;&gt;Add Disqus comment&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;a5b53f372baa85f2657699addd3640e086188756&quot;&gt;19 May 2015&lt;&#x2F;a&gt; » Add &lt;code&gt;featured notes&lt;&#x2F;code&gt; in &lt;a href=&quot;https:&#x2F;&#x2F;thadaw.com&#x2F;posts&#x2F;my-blog-development&#x2F;%7B%7Bsite.baseurl%7D%7D&#x2F;notes&#x2F;&quot;&gt;Note page&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;0b30a3c10a593ee4aeeba400ec08efe531b09451&quot;&gt;19 May 2015&lt;&#x2F;a&gt; » Add &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ghiculescu&#x2F;jekyll-table-of-contents&quot;&gt;Table of Contents for Jekyll&lt;&#x2F;a&gt; in &lt;code&gt;post layout&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;24 Jun 2015 » Make this blog to multilanguage :D&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;c37ff03a3f6af823014bb2df4fdefa4809c90273&quot;&gt;28 Oct 2015&lt;&#x2F;a&gt; » Move to &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;travis-ci.org&#x2F;mildronize&#x2F;mildronize.github.io&quot;&gt;Travis-CI&lt;&#x2F;a&gt; (Build Jekyll site with Travis-CI)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mildronize&#x2F;mildronize.github.io&#x2F;commit&#x2F;ec636fc39654c82e3b5d2a0d295bbf5d659f9748&quot;&gt;28 jan 2016&lt;&#x2F;a&gt; » Use &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.docker.com&#x2F;&quot;&gt;Docker&lt;&#x2F;a&gt; instead Jekyll packages on Debian for development and writing a blog.&lt;&#x2F;li&gt;
&lt;li&gt;30 jan 2016 » Combine Thai language into my main blog (This web includes with Thai and English posts).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;next-plans&quot;&gt;Next Plans&lt;a class=&quot;zola-anchor&quot; href=&quot;#next-plans&quot; aria-label=&quot;Anchor link for: next-plans&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Build a tools for auto generate prototype of post (YAML header)
&lt;ul&gt;
&lt;li&gt;Convert to title string to lowercase of string and dash.&lt;&#x2F;li&gt;
&lt;li&gt;Generate simple YAML file.&lt;&#x2F;li&gt;
&lt;li&gt;It&#x27;s called &#x27;Tools&#x27; page.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Fix Related post to show only the posts that have related tags&lt;&#x2F;li&gt;
&lt;li&gt;Auto complete search&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;vvv.tobiassjosten.net&#x2F;jekyll&#x2F;jekyll-tag-cloud&#x2F;&quot;&gt;Cloud tags&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Simple SOAP client and simple server via flask</title>
		<published>2015-05-04T00:00:00+00:00</published>
		<updated>2015-05-04T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/simple-soap-client-and-simple-server-via-flask/" type="text/html"/>
		<id>https://thadaw.com/posts/simple-soap-client-and-simple-server-via-flask/</id>
		<content type="html">&lt;h2 id=&quot;objective&quot;&gt;Objective:&lt;a class=&quot;zola-anchor&quot; href=&quot;#objective&quot; aria-label=&quot;Anchor link for: objective&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;To get current oil price in Thailand via SOAP and response in JSON format.
SOAP Server URL for this scirpt: &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.pttplc.com&#x2F;webservice&#x2F;pttinfo.asmx?WSDL&quot;&gt;http:&#x2F;&#x2F;www.pttplc.com&#x2F;webservice&#x2F;pttinfo.asmx?WSDL&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;prerequisite&quot;&gt;Prerequisite:&lt;a class=&quot;zola-anchor&quot; href=&quot;#prerequisite&quot; aria-label=&quot;Anchor link for: prerequisite&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Python 3.4&lt;&#x2F;li&gt;
&lt;li&gt;flask&lt;&#x2F;li&gt;
&lt;li&gt;flask-cors&lt;&#x2F;li&gt;
&lt;li&gt;suds-jurko&lt;&#x2F;li&gt;
&lt;li&gt;xmltodict&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This script is located in &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;mildronize&#x2F;56a35fb6d26d0e9002a1&quot;&gt;https:&#x2F;&#x2F;gist.github.com&#x2F;mildronize&#x2F;56a35fb6d26d0e9002a1&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python z-code&quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt;!&#x2F;usr&#x2F;bin&#x2F;python3
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-from z-python&quot;&gt;from&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-meta z-import-source z-python&quot;&gt; &lt;span class=&quot;z-meta z-import-path z-python&quot;&gt;&lt;span class=&quot;z-meta z-import-name z-python&quot;&gt;flask&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-python&quot;&gt;import&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt; &lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;Flask&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-from z-python&quot;&gt;from&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-meta z-import-source z-python&quot;&gt; &lt;span class=&quot;z-meta z-import-path z-python&quot;&gt;&lt;span class=&quot;z-meta z-import-name z-python&quot;&gt;flask&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-python&quot;&gt;import&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt; &lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-import-list z-python&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;jsonify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-from z-python&quot;&gt;from&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-meta z-import-source z-python&quot;&gt; &lt;span class=&quot;z-meta z-import-path z-python&quot;&gt;&lt;span class=&quot;z-meta z-import-name z-python&quot;&gt;flask&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-import-name z-python&quot;&gt;ext&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-import-name z-python&quot;&gt;cors&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-python&quot;&gt;import&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt; &lt;span class=&quot;z-variable z-other z-constant z-python&quot;&gt;CORS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-from z-python&quot;&gt;from&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-meta z-import-source z-python&quot;&gt; &lt;span class=&quot;z-meta z-import-path z-python&quot;&gt;&lt;span class=&quot;z-meta z-import-name z-python&quot;&gt;suds&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-import-name z-python&quot;&gt;client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-python&quot;&gt;import&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt; &lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;Client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-python&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;xmltodict&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;Flask&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-support z-variable z-magic z-python&quot;&gt;__name__&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;cors&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;CORS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-python&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-annotation z-function z-python&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-annotation z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-annotation z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;route&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-annotation z-function z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-annotation z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;&#x2F;apis&#x2F;get-oil-price&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-arguments z-python&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-python&quot;&gt;methods&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-sequence z-list z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-python&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;POST&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-python&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-annotation z-function z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function z-python&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;&lt;span class=&quot;z-keyword z-declaration z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;get_oil_price&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-function z-begin z-python&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt; Get variable from http POST
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;date_string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt;str&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;form&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-python&quot;&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;date&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-python&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;date_string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;date_string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;split&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;-&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;day&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;date_string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-python&quot;&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-arguments z-python&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-python&quot;&gt;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-python&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;month&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;date_string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-python&quot;&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-arguments z-python&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-python&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-python&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;year&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;date_string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-python&quot;&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-arguments z-python&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-python&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-python&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt; Get SOAP Service via suds
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;url&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;http:&#x2F;&#x2F;www.pttplc.com&#x2F;webservice&#x2F;pttinfo.asmx?WSDL&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;Client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;url&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt; Execute GetOilPrice method of SOAP
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;xml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;client&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;GetOilPrice&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;EN&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-arguments z-python&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;day&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-arguments z-python&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;month&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-arguments z-python&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;year&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt; Convert XML to dict
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;res_dict&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;xmltodict&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;parse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;xml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-mapping z-empty z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-python&quot;&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;result&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-python&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;res_dict&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-python&quot;&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;PTT_DS&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-python&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-python&quot;&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;DataAccess&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-python&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt; Convert dict to JSON
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-flow z-return z-python&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;jsonify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-python&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-annotation z-function z-python&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-annotation z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-annotation z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;route&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-annotation z-function z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-annotation z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;&#x2F;apis&#x2F;current-oil-price&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-arguments z-python&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-python&quot;&gt;methods&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-sequence z-list z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-python&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;GET&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-python&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-annotation z-function z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function z-python&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;&lt;span class=&quot;z-keyword z-declaration z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;oil_current_price&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-function z-begin z-python&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt; Get SOAP Service via suds
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;url&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;http:&#x2F;&#x2F;www.pttplc.com&#x2F;webservice&#x2F;pttinfo.asmx?WSDL&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;Client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;url&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt; Execute CurrentOilPrice method of SOAP
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;xml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;client&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;CurrentOilPrice&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;EN&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt; Convert XML to dict
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;res_dict&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;xmltodict&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;parse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;xml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-mapping z-empty z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-python&quot;&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;result&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-python&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;res_dict&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-python&quot;&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;PTT_DS&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-python&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-python&quot;&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-arguments z-python&quot;&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;DataAccess&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-python&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt; Convert dict to JSON
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-flow z-return z-python&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;jsonify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-statement z-conditional z-if z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-if z-python&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-support z-variable z-magic z-python&quot;&gt;__name__&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-python&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-python&quot;&gt;__main__&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-block z-conditional z-if z-python&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-python&quot;&gt;host&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;0.0.0.0&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>How to setup this blog?</title>
		<published>2015-05-03T00:00:00+00:00</published>
		<updated>2015-05-03T00:00:00+00:00</updated>
		<link href="https://thadaw.com/posts/how-to-setup-this-blog/" type="text/html"/>
		<id>https://thadaw.com/posts/how-to-setup-this-blog/</id>
		<content type="html">&lt;p&gt;I&#x27;m following &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;dev.im-bot.com&#x2F;2014&#x2F;06&#x2F;16&#x2F;how-to-set-up-this-blog&#x2F;&quot;&gt;botbotbot &#x27;s blog&lt;&#x2F;a&gt; to setup this blog. Some contents of this post is original from him.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;This blog created by Jekyll that is ruby scripts to transforms plain text into static html website and blogs and hosted on Github Page that free hosting support Jekyll.This blog use Lanyon theme that based on Poole a minimal style of Jekyll.&quot; botbotbot said.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;All of below steps are same as &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;dev.im-bot.com&#x2F;2014&#x2F;06&#x2F;16&#x2F;how-to-set-up-this-blog&#x2F;&quot;&gt;botbotbot &#x27;s blog&lt;&#x2F;a&gt;, but I have used &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;hyde.getpoole.com&#x2F;&quot;&gt;Hyde&lt;&#x2F;a&gt; theme intead.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;set-up-github-page&quot;&gt;Set up github page:&lt;a class=&quot;zola-anchor&quot; href=&quot;#set-up-github-page&quot; aria-label=&quot;Anchor link for: set-up-github-page&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Follow setup guilde of Github page for more information about jekyll on github look at&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;http:&#x2F;&#x2F;help.github.com&#x2F;articles&#x2F;using-jekyll-with-pages
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Clone project from &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;hyde.getpoole.com&#x2F;&quot;&gt;Hyde&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;git clone https:&#x2F;&#x2F;github.com&#x2F;poole&#x2F;hyde.git
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Configs jekyll in &lt;code&gt;_config.yml&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml z-code&quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-line z-number-sign z-yaml&quot;&gt;#&lt;&#x2F;span&gt; Setup
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;title&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;            &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;Mildronize&amp;#39;s blog&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;tagline&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;          &lt;span class=&quot;z-string z-quoted z-single z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;mildronize-blog&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;description&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;      &lt;span class=&quot;z-string z-quoted z-single z-yaml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;My dev blog&lt;span class=&quot;z-punctuation z-definition z-string z-end z-yaml&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;url&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;              &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;http:&#x2F;&#x2F;mildronize.github.io&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;baseurl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;          &lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-yaml&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-plain z-out z-yaml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;paginate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-mapping z-yaml&quot;&gt;:&lt;&#x2F;span&gt;         &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-yaml&quot;&gt;5&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Make tags.md in root directory copy code from&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; https:&#x2F;&#x2F;github.com&#x2F;LanyonM&#x2F;lanyonm.github.io&#x2F;blob&#x2F;master&#x2F;tags.html
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Let blog it.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;next-step&quot;&gt;Next Step&lt;a class=&quot;zola-anchor&quot; href=&quot;#next-step&quot; aria-label=&quot;Anchor link for: next-step&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;milanaryal.com&#x2F;2015&#x2F;adding-hover-anchor-links-to-header-on-github-pages-using-jekyll&quot;&gt;Add hover anchor links to header on GitHub Pages using Jekyll&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;note&quot;&gt;Note:&lt;a class=&quot;zola-anchor&quot; href=&quot;#note&quot; aria-label=&quot;Anchor link for: note&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;If you got the message from jekyll build(or serve) &lt;code&gt;Liquid Exception: Failed to get header.&lt;&#x2F;code&gt;, try to check your python version that is python 2.7.&lt;&#x2F;p&gt;
&lt;p&gt;See full instruction from &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;akenn.org&#x2F;blog&#x2F;Liquid-Exception-Jekyll&#x2F;&quot;&gt;http:&#x2F;&#x2F;akenn.org&#x2F;blog&#x2F;Liquid-Exception-Jekyll&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;recommended-resources&quot;&gt;Recommended Resources&lt;a class=&quot;zola-anchor&quot; href=&quot;#recommended-resources&quot; aria-label=&quot;Anchor link for: recommended-resources&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;jmcglone.com&#x2F;guides&#x2F;github-pages&#x2F;&quot;&gt;Creating and Hosting a Personal Site on GitHub from scratch (step by step)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;related-resources&quot;&gt;Related Resources&lt;a class=&quot;zola-anchor&quot; href=&quot;#related-resources&quot; aria-label=&quot;Anchor link for: related-resources&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;git-github-and-github-pages&quot;&gt;Git, GitHub, and GitHub Pages&lt;a class=&quot;zola-anchor&quot; href=&quot;#git-github-and-github-pages&quot; aria-label=&quot;Anchor link for: git-github-and-github-pages&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;git-scm.com&#x2F;doc&quot;&gt;Git Documentation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;try.github.io&#x2F;levels&#x2F;1&#x2F;challenges&#x2F;1&quot;&gt;Learn Git and GitHub in 15 minutes&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;help.github.com&#x2F;articles&#x2F;github-glossary&quot;&gt;GitHub Glossary&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;help.github.com&#x2F;&quot;&gt;GitHub Help&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tiimgreen&#x2F;github-cheat-sheet&quot;&gt;GitHub Cheat Sheet&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;blogs.lse.ac.uk&#x2F;impactofsocialsciences&#x2F;2013&#x2F;06&#x2F;04&#x2F;github-for-academics&#x2F;&quot;&gt;GitHub For Academics&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;help.github.com&#x2F;categories&#x2F;20&#x2F;articles&quot;&gt;GitHub Pages Help&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;jekyll&quot;&gt;Jekyll&lt;a class=&quot;zola-anchor&quot; href=&quot;#jekyll&quot; aria-label=&quot;Anchor link for: jekyll&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jekyll&#x2F;jekyll&#x2F;wiki&#x2F;Sites&quot;&gt;Sites Using Jekyll&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;import.jekyllrb.com&#x2F;docs&#x2F;home&#x2F;&quot;&gt;Blog Migrations to Jekyll&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;markdown&quot;&gt;Markdown&lt;a class=&quot;zola-anchor&quot; href=&quot;#markdown&quot; aria-label=&quot;Anchor link for: markdown&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;daringfireball.net&#x2F;projects&#x2F;markdown&#x2F;&quot;&gt;Official Markdown Spec&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;packetlife.net&#x2F;media&#x2F;library&#x2F;16&#x2F;Markdown.pdf&quot;&gt;Printable Markdown Cheatsheet&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;adam-p&#x2F;markdown-here&#x2F;wiki&#x2F;Markdown-Cheatsheet&quot;&gt;Markdown Cheatsheet&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;help.github.com&#x2F;articles&#x2F;github-flavored-markdown&quot;&gt;GitHub Flavored Markdown&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
</feed>