<?xml version="1.0"?>
<rss version="2.0">

<channel>
	<title>Planet TLWG</title>
	<link>http://linux.thai.net/planet</link>
	<language>en</language>
	<description>Planet TLWG - http://linux.thai.net/planet</description>

<item>
	<title>Vee: Validating Native Python: A Practical Approach with baredtype</title>
	<guid>https://dev.to/veer66/validating-native-python-a-practical-approach-with-baredtype-44g1</guid>
	<link>https://dev.to/veer66/validating-native-python-a-practical-approach-with-baredtype-44g1</link>
	<description>&lt;p&gt;In Python development, we often default to using basic data structures like &lt;code&gt;dict&lt;/code&gt; and &lt;code&gt;list&lt;/code&gt; to move data around. They are flexible, JSON-compatible, and require no special setup. With the recent advancements in &lt;code&gt;TypedDict&lt;/code&gt; and &lt;code&gt;Annotated&lt;/code&gt;, the Python type system has become powerful enough to describe these structures with high precision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;baredtype&lt;/strong&gt; is a library built to bridge the gap between these native structures and formal validation. It allows you to enforce strict rules on your data without ever forcing that data to change its shape or type.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Strength of Basic Data Structures
&lt;/h2&gt;

&lt;p&gt;The main draw of &lt;code&gt;baredtype&lt;/code&gt; is that it works directly with the data structures you already use. There is no custom class instantiation or &quot;wrapping&quot; of data into library-specific objects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Serialization and Deserialization
&lt;/h3&gt;

&lt;p&gt;Because your data remains a standard &lt;code&gt;list&lt;/code&gt; or &lt;code&gt;dict&lt;/code&gt;, you don't need special methods to get your data in or out of a system. You use the standard tools you already know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;To JSON:&lt;/strong&gt; &lt;code&gt;json.dumps(my_data)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;From JSON:&lt;/strong&gt; &lt;code&gt;json.loads(input_string)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation:&lt;/strong&gt; &lt;code&gt;validate(MySchema, my_data)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Handling Keys and &lt;code&gt;None&lt;/code&gt; Values
&lt;/h3&gt;

&lt;p&gt;Working with native structures means using standard Python idioms. &lt;code&gt;baredtype&lt;/code&gt; respects &lt;code&gt;TypedDict&lt;/code&gt; definitions for required fields and &lt;code&gt;Annotated&lt;/code&gt; for value constraints, allowing you to handle &lt;code&gt;None&lt;/code&gt; values and missing keys naturally.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight python&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typing_extensions&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TypedDict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NotRequired&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Annotated&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;baredtype&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;validate&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TypedDict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Annotated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;^[\w.-]+@[\w.-]+\.\w+$&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NotRequired&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Use standard Python to check your data:
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;tech_lead&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;No email provided.&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Age is an optional key.&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Validation checks the types and the constraints
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_valid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UserData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Mapping to JSON Schema and OpenAPI
&lt;/h2&gt;

&lt;p&gt;A core objective of &lt;code&gt;baredtype&lt;/code&gt; is making it easy to map Python types to external standards like JSON Schema and OpenAPI. It handles the &quot;quantifiers&quot; that define how different types can be combined.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quantifier Logic
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;oneOf&lt;/code&gt;&lt;/strong&gt;: By using &lt;code&gt;Annotated&lt;/code&gt; metadata, you can specify that data must match &lt;strong&gt;exactly one&lt;/strong&gt; type in a Union. This is crucial for precise API definitions where ambiguity can lead to bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;allOf&lt;/code&gt;&lt;/strong&gt;: This is naturally supported through &lt;code&gt;TypedDict&lt;/code&gt; inheritance. When one &lt;code&gt;TypedDict&lt;/code&gt; inherits from others, &lt;code&gt;baredtype&lt;/code&gt; generates a schema representing the union of those requirements, staying consistent with OpenAPI standards.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Two Ways to Verify the Spec
&lt;/h2&gt;

&lt;p&gt;When we define our data structures, we are writing a specification for our code. There are two primary ways to ensure our code follows this spec, both of which are supported by &lt;code&gt;baredtype&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Static Type Checking
&lt;/h3&gt;

&lt;p&gt;Because the library is built on &lt;code&gt;TypedDict&lt;/code&gt;, you get the full benefit of tools like &lt;strong&gt;Mypy&lt;/strong&gt; or &lt;strong&gt;Pyright&lt;/strong&gt;. Your IDE can catch missing keys or type mismatches while you are writing the code. This finds errors before the code ever runs.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Property-Based Checking
&lt;/h3&gt;

&lt;p&gt;While static types prove what &lt;em&gt;should&lt;/em&gt; happen, property-based checking proves what &lt;em&gt;can&lt;/em&gt; happen under stress. &lt;code&gt;baredtype&lt;/code&gt; integrates with &lt;strong&gt;Hypothesis&lt;/strong&gt; to automatically generate data that fits your &lt;code&gt;TypedDict&lt;/code&gt; definitions, including constraints like &lt;code&gt;min_length&lt;/code&gt; or regex patterns.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight python&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;baredtype&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;given_from_annotations&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@given_from_annotations&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test_process_payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UserData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Hypothesis generates a wide variety of valid UserData dicts
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# to find edge cases in your logic.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;my_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Validation: The Constant Requirement
&lt;/h3&gt;

&lt;p&gt;Regardless of whether you use static checking, property-based checking, or both, &lt;strong&gt;runtime validation is a must.&lt;/strong&gt; External data is inherently untrusted. Static checking verifies your internal logic, and property-based testing verifies your code's resilience during development. At the moment data enters your system, &lt;code&gt;baredtype&lt;/code&gt; provides the final, essential check to ensure the data actually matches your specification.&lt;/p&gt;




&lt;h2&gt;
  
  
  Explore the Project
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;baredtype&lt;/code&gt; offers a lightweight validation layer that stays out of your data's way, leveraging the emerging strengths of the Python type system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check out the project on Codeberg:&lt;/strong&gt;&lt;br /&gt;
👉 &lt;a href=&quot;https://codeberg.org/veer66/baredtype&quot; rel=&quot;noopener noreferrer&quot;&gt;https://codeberg.org/veer66/baredtype&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Mon, 19 Jan 2026 00:35:05 +0000</pubDate>
</item>
<item>
	<title>Thep: Addressing fonts-arundina Unreproducibility</title>
	<guid>tag:blogger.com,1999:blog-6815053.post-8276353509251472387</guid>
	<link>http://thep.blogspot.com/2026/01/addressing-fonts-arundina.html</link>
	<description>&lt;p&gt;มีเวลากลับมาทำงานของ Debian รอบนี้ เรื่องหนึ่งที่ทิ้งคาราคาซังไว้นานคือ &lt;a href=&quot;https://tests.reproducible-builds.org/debian/rb-pkg/unstable/amd64/diffoscope-results/fonts-arundina.html&quot;&gt;ปัญหา unreproducible ของ fonts-arundina&lt;/a&gt; ที่สาเหตุหลักเกิดจาก timestamp ที่ Fontforge สร้าง&lt;/p&gt;

&lt;p&gt;ความจริงปัญหานี้ควรหมดไปนานแล้ว ตั้งแต่มี&lt;a href=&quot;https://reproducible-builds.org/specs/source-date-epoch/&quot;&gt;ข้อกำหนด SOURCE_DATE_EPOCH&lt;/a&gt; เพื่อให้ซอฟต์แวร์ต่างๆ ใช้ timestamp จาก changelog ล่าสุดของ distro แทนการใช้เวลาขณะ build ที่เปลี่ยนไปเรื่อยในการ build แต่ละครั้ง และ FontForge ก็ได้รับแพตช์ที่ Debian เสนอไปตั้งนานแล้วใน &lt;a href=&quot;https://github.com/fontforge/fontforge/issues/2490&quot;&gt;fontforge#2490&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ก่อนหน้านี้ผมเคยตรวจสอบมารอบหนึ่งแล้ว ก็ยังไม่เจอสาเหตุของปัญหา จึงสรุปว่าจะ workaround ไปก่อนด้วยการตัด timestamp ออกเสียเลยใน 2 commit (&lt;a href=&quot;https://github.com/tlwg/fonts-arundina/commit/3668e710048933a6b226311647247f4f03a30d11&quot;&gt;ใช้ sed ตัดข้อมูลใน AFM และ PFB โดยตรง&lt;/a&gt;, &lt;a href=&quot;https://github.com/tlwg/fonts-arundina/commit/5f2268005d1b37a5877c349e40379a6afb2125a1&quot;&gt;ปรับวิธีการตัดข้อมูลใน PFB ซึ่งเป็น binary&lt;/a&gt;) โดยนอกจาก timestamp แล้ว ก็ตัดข้อมูล &lt;code&gt;Creator&lt;/code&gt; ที่ดันไปเอาข้อมูล user ของ build process มาแปะออกด้วย เพราะมันทำให้ขึ้นอยู่กับคนที่สั่ง build deb ซึ่งจะเป็นใครก็ได้&lt;/p&gt;

&lt;p&gt;แต่ก็ยังเหลือปัญหาข้อมูล &lt;code&gt;ItalicAngle&lt;/code&gt; ที่อาจใช้ comma แทนจุดทศนิยมอยู่ ซึ่งเป็นพฤติกรรมที่ขึ้นกับ locale ของระบบที่ build&lt;/p&gt;

&lt;p&gt;แต่หลังจากที่ตัดข้อมูล creation ออกไปแล้ว ก็อยากแกะรอยหาปัญหาที่แท้จริงของ FontForge อีกสักตั้ง นั่งไล่โค้ดก็เห็นใช้ค่าจาก &lt;code&gt;SOURCE_DATE_EPOCH&lt;/code&gt; ในฟังก์ชัน &lt;code&gt;GetTime()&lt;/code&gt; ที่ใช้อยู่ทั่วทั้งแอปอยู่แล้ว ถ้าเช่นนั้น timestamp มันยัง vary อยู่ได้ยังไง?&lt;/p&gt;

&lt;p&gt;รอบนี้ได้คำตอบจนได้ คือ timestamp มันเป็นสตริงที่สร้างด้วยฟังก์ชัน &lt;code&gt;ctime()&lt;/code&gt; ของ Standard C Library ซึ่งมีการพิจารณา timezone ที่ initialize ไว้โดยฟังก์ชัน &lt;code&gt;tzset()&lt;/code&gt; ด้วย โดยถ้าตัวแปร environment &lt;code&gt;TZ&lt;/code&gt; มีการกำหนดค่า ก็จะมีการชดเชยนาฬิกากลับเป็น GMT ตาม timezone ที่กำหนด ซึ่งถ้าระบบที่ build เกิดมีการกำหนด &lt;code&gt;TZ&lt;/code&gt; ขึ้นมา มันก็จะปรับค่า epoch ใน &lt;code&gt;$SOURCE_DATE_EPOCH&lt;/code&gt; จาก timezone ใน &lt;code&gt;$TZ&lt;/code&gt; ให้เป็น GMT แต่ปัญหาคือ epoch ใน &lt;code&gt;$SOURCE_DATE_EPOCH&lt;/code&gt; มันเป็น GMT อยู่แล้วตั้งแต่ต้น ไปปรับซ้ำอีกมันก็เลยเพี้ยน!&lt;/p&gt;

&lt;p&gt;กล่าวคือ โปรแกรม &lt;a href=&quot;https://salsa.debian.org/reproducible-builds/reprotest&quot;&gt;&lt;code&gt;reprotest&lt;/code&gt;&lt;/a&gt; ได้กำหนดการกลั่นแกล้งไว้ด้วยตัวแปร environment &lt;code&gt;TZ&lt;/code&gt; ใครไม่ระวังเรื่องนี้ก็ fail นั่นเอง&lt;/p&gt;

&lt;p&gt;สรุปรวบยอดว่าปัญหา unreproducible ของ &lt;code&gt;fonts-arundina&lt;/code&gt; และวิธีแก้คือ:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt; timestamp ของ Creation Date เพี้ยน: แก้โดยกำหนด environment &lt;code&gt;TZ=GMT&lt;/code&gt; &lt;/li&gt;
  &lt;li&gt; ข้อมูล Creator ที่ไปอ่านข้อมูลจาก user ID ของโพรเซสที่ build มาแปะ: แก้โดย override environment &lt;code&gt;USER=&quot;&lt;em&gt;&amp;lt;ชื่อผู้แก้ไขฟอนต์ล่าสุด&amp;gt;&lt;/em&gt;&quot;&lt;/code&gt; &lt;/li&gt;
  &lt;li&gt; ค่า &lt;code&gt;ItalicAngle&lt;/code&gt; มีรูปแบบทศนิยมที่ขึ้นอยู่กับ locale: แก้โดยกำหนด locale ด้วย &lt;code&gt;LC_ALL=C&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ด้วยวิธีแก้ข้างต้น เราจะสามารถ revert การตัดข้อมูลการ create ฟอนต์ออก แล้วคงข้อมูลดังกล่าวแบบ reproducible ได้ แลกกับความรกรุงรังของคำสั่ง build นิดหน่อย&lt;/p&gt;

&lt;p&gt;แต่จะคงข้อมูลการ create ไว้หรือไม่? ก็ต้องตอบคำถามว่า ข้อมูล creation date, creator มีประโยชน์อะไรไหม? มันอาจช่วยแยกแยะ version ของฟอนต์ได้? ถ้ายังมีประโยชน์ก็อาจเอากลับมา ไม่งั้นก็ตัดทิ้ง&lt;/p&gt;

&lt;p&gt;คิดสะระตะแล้ว ข้อมูล creation date, creator อาจเคยมีประโยชน์เมื่อนักพัฒนาฟอนต์เก็บไฟล์ source ไว้กับตัว จะปล่อยฟอนต์เมื่อไรก็ generate ทำให้ข้อมูลการ create บ่งบอกการ release แต่พอเป็น open source ที่ทุกคนสามารถมี source อยู่ในมือ ผู้พัฒนากับผู้ generate ก็อาจเป็นคนละคนกัน การพยายามบอกว่าใครเป็นผู้ generate จึงไม่มีความหมายเท่าไร ในเมื่อ generate แต่ละครั้งก็มาจาก source เดิม เนื้อหาก็คงเดิม&lt;/p&gt;

&lt;p&gt;ข้อมูลที่ควรจำแนกเนื้อหาฟอนต์ได้ดีกว่าคือฟิลด์ &lt;code&gt;Version&lt;/code&gt; ในฟอนต์ ที่ผู้พัฒนาควรปรับค่าทุกครั้งที่ปล่อยอยู่แล้ว&lt;/p&gt;

&lt;p&gt;สรุป: ไม่เอาข้อมูลการ create กลับมา ตัดแล้วตัดเลย ทำเพิ่มคือ&lt;a href=&quot;https://github.com/tlwg/fonts-arundina/commit/768e85b4cbbd3869ce2736fb32fc6c5d0526ee52&quot;&gt;การบังคับ C locale&lt;/a&gt; เพื่อควบคุมรูปแบบจุดทศนิยม&lt;/p&gt;</description>
	<pubDate>Thu, 08 Jan 2026 08:13:00 +0000</pubDate>
	<author>noreply@blogger.com (Thep)</author>
</item>
<item>
	<title>Vee: Revisiting codebase organization practices from 2004</title>
	<guid>https://dev.to/veer66/revisiting-codebase-organization-practices-from-2004-5ej0</guid>
	<link>https://dev.to/veer66/revisiting-codebase-organization-practices-from-2004-5ej0</link>
	<description>&lt;p&gt;I reviewed the file and directory structure of several web-based free software projects released in 2003–2004: the Koha 1.2.0 library management system, the MRBS 1.2.1 meeting room booking system, and the DSpace 1.2 content repository system. These were written in Perl, PHP, and Java, respectively.&lt;/p&gt;

&lt;p&gt;Endpoint files are named using an action, optionally followed by an entity, following patterns such as search.pl, &lt;code&gt;search.php&lt;/code&gt;, &lt;code&gt;SimpleSearchServlet.java&lt;/code&gt;, &lt;code&gt;updatebibitem.pl&lt;/code&gt;, &lt;code&gt;edit_entry.php&lt;/code&gt;, and &lt;code&gt;EditProfileServlet.java&lt;/code&gt;. These verbs or verb phrases may or may not align with user workflows. For example, Koha includes &lt;code&gt;opac_reserve.pl&lt;/code&gt;, indicating it handles the reservation workflow via the Online Public Access Catalog (OPAC) API. However, there is no dedicated &quot;borrow&quot; endpoint file.&lt;/p&gt;

&lt;p&gt;Each system is designed in a modular style. Koha has a &lt;code&gt;Borrower.pm&lt;/code&gt; module that provides a &lt;code&gt;reserveslist&lt;/code&gt; function; MRBS uses &lt;code&gt;functions.inc&lt;/code&gt; with functions such as &lt;code&gt;make_room_select_html&lt;/code&gt;; and DSpace's &lt;code&gt;Item.java&lt;/code&gt; includes methods like &lt;code&gt;findAll&lt;/code&gt;. That said, they do not strictly follow a multi-tier architecture, for instance, database queries are not isolated into a dedicated data access layer. Still, DSpace, by using Servlets and JSPs, does establish a distinct presentation layer.&lt;/p&gt;

&lt;p&gt;Because of the verb-based naming convention, files emphasize what they do rather than which architectural layer they belong to. This makes their purpose easy to understand at a glance.&lt;/p&gt;

&lt;p&gt;However, this approach can make organization and testing more challenging. Logic, database queries, and presentation code are often mixed; sometimes not even separated into distinct functions.&lt;/p&gt;</description>
	<pubDate>Sat, 27 Dec 2025 02:06:57 +0000</pubDate>
</item>
<item>
	<title>Vee: Global Variables in Python Are Not That Global</title>
	<guid>https://dev.to/veer66/global-variables-in-python-are-not-that-global-280j</guid>
	<link>https://dev.to/veer66/global-variables-in-python-are-not-that-global-280j</link>
	<description>&lt;p&gt;In the context of programming in the 1980s, &quot;global variables&quot; likely brings to mind languages like &lt;a href=&quot;https://en.wikipedia.org/wiki/MBASIC&quot; rel=&quot;noopener noreferrer&quot;&gt;MBASIC&lt;/a&gt;. However, using MBASIC as an example today would be challenging, as it is now rarely used or known. Instead, GNU Bash, which is the default shell scripting language for many systems—will be used to illustrate what global variables were traditionally like. Anyway, some might think of Fortran II, but I'm not familiar with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bash Example
&lt;/h2&gt;

&lt;p&gt;I wrote a Bash script consisting of four files:&lt;/p&gt;

&lt;h3&gt;
  
  
  a.bash
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;a.bash&lt;/code&gt; orchestrates everything. &quot;Orchestration&quot; might be too grand a word for these toy scripts, but I want to convey that it performs a role similar to Apache Airflow.&lt;br /&gt;
&lt;/p&gt;

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

&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; ./b.bash
&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; ./c.bash
&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; ./d.bash

init
print_count
inc
print_count
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  b.bash
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;b.bash&lt;/code&gt; contains only one function, &lt;code&gt;inc&lt;/code&gt;, which increments the counter, which is the global variable in this example.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;inc&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;counter &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  c.bash
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;c.bash&lt;/code&gt; contains &lt;code&gt;print_count&lt;/code&gt;, which simply displays the value of the global variable &lt;code&gt;counter&lt;/code&gt;.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;print_count&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$counter&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  d.bash
&lt;/h3&gt;

&lt;p&gt;In Bash, &lt;code&gt;counter&lt;/code&gt; can be initialized globally from within a function by default.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;init&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Python Example
&lt;/h2&gt;

&lt;p&gt;The following section shows the result of porting the Bash script above to Python, highlighting the key differences.&lt;/p&gt;

&lt;h2&gt;
  
  
  a.py
&lt;/h2&gt;

&lt;p&gt;This is the orchestration part. Note the use of namespaces or module names.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight python&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;print_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;print_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  b.py
&lt;/h2&gt;

&lt;p&gt;In the Python version, &lt;code&gt;inc&lt;/code&gt; must refer to the module &lt;code&gt;d&lt;/code&gt; to access the variable. Alternatively, &lt;code&gt;counter&lt;/code&gt; could be explicitly imported.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight python&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  c.py
&lt;/h2&gt;

&lt;p&gt;Similarly, &lt;code&gt;print_count&lt;/code&gt; in Python must also refer to module &lt;code&gt;d&lt;/code&gt;.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight python&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;print_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  d.py
&lt;/h2&gt;

&lt;p&gt;Unlike in Bash, initializing a global variable from within a function—even in the same module—requires an explicit &lt;code&gt;global&lt;/code&gt; declaration.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight python&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Differences
&lt;/h2&gt;

&lt;p&gt;As you can see, a global variable in Bash is truly global across files. In Python, however, a global variable is only global within its module, i.e., file. Furthermore, mutating a global variable in Bash requires no special syntax, whereas in Python a function must explicitly declare &lt;code&gt;global&lt;/code&gt; to modify a module-level variable.&lt;/p&gt;

&lt;p&gt;Consequently, although both are called &quot;global variables,&quot; Python's are scoped to the module. This means they won’t interfere with variables in other modules unless we deliberately make them do so. For developers who use one class per module, a Python global variable behaves much like a class variable. Additionally, variable assignment inside a Python function is local by default, preventing accidental modification of global state unless explicitly intended.&lt;/p&gt;

&lt;p&gt;In short, many traditional precautions about global variables in languages like Bash or MBASIC no longer apply in Python. Therefore, we might reconsider automatically rejecting global variables based on past advice and instead evaluate their use case thoughtfully.&lt;/p&gt;</description>
	<pubDate>Sat, 13 Dec 2025 05:51:25 +0000</pubDate>
</item>
<item>
	<title>Vee: A lesson about abstraction from Arch Linux</title>
	<guid>https://dev.to/veer66/a-lesson-about-abstraction-from-arch-linux-3e98</guid>
	<link>https://dev.to/veer66/a-lesson-about-abstraction-from-arch-linux-3e98</link>
	<description>&lt;p&gt;I was impressed by &lt;a href=&quot;https://www.pkgsrc.org/&quot; rel=&quot;noopener noreferrer&quot;&gt;pkgsrc&lt;/a&gt; because it is a powerful package management system that defines packages using a common tool like a Makefile. I later discovered that the &lt;a href=&quot;https://wiki.archlinux.org/title/PKGBUILD&quot; rel=&quot;noopener noreferrer&quot;&gt;PKGBUILD&lt;/a&gt; file is even more impressive, as its purpose is immediately clear. I initially attributed this to my greater familiarity with Bash scripting compared to Makefiles, but I now believe the true reason is PKGBUILD's level of abstraction.&lt;/p&gt;

&lt;p&gt;It retains explicit calls to configure and make, preserving the transparency of a manual installation. This demonstrates that while increased abstraction can make code shorter, it can also hinder understanding.&lt;/p&gt;

&lt;p&gt;Another potential advantage of greater abstraction is the ability to change the configure command for every package by modifying just one location. However, since GNU Autotools has continued to use the configure command for decades, it may not be worth sacrificing clarity for this particular benefit.&lt;/p&gt;</description>
	<pubDate>Sun, 23 Nov 2025 09:23:50 +0000</pubDate>
</item>
<item>
	<title>Kitt: หยี่แปะ</title>
	<guid>https://kitty.in.th/?p=20749</guid>
	<link>https://kitty.in.th/index.php/2025/10/25/%e0%b8%ab%e0%b8%a2%e0%b8%b5%e0%b9%88%e0%b9%81%e0%b8%9b%e0%b8%b0/</link>
	<description>อากง อาม่า ของ อจก. เป็นจีนแต้จิ๋ว อพยพหนีความแร้นแค้นมาจากซัวเถา เมื่อเกือบจะร้อยปีก่อน มีลูก 5 คน พอมาอยู่ไทยเลยใช้นามสกุล แซ่เตีย (张) ตามอากง จนลุงคนรอง (หยี่แปะ) ไปขอจดใช้นามสกุล ธโนปจัย ภายหลังพบว่าไปซ้ำกับนามสกุลที่มีมาก่อนแล้ว เลยเปลี่ยนเป็น “เธียรธโนปจัย” ลุงน่าจะเป็นคนเดียวในครอบครัวเราที่เคยใช้นามสกุล ธโนปจัย ปรากฏ ชื่อ-สกุล ในวิทยานิพนธ์ ป.โท ของจุฬาฯ ปี 2517 ก่อนจะเปลี่ยนมาใช้ เธียรธโนปจัย ด้วยกันหลังจากนั้น ลุงทำงานธนาคาร ไปสุดตำแหน่งใหญ่ใน HQ แถวสีลม ไม่มีครอบครัว สันโดษ early มา day trade ดูแลอาม่าช่วงก่อนอาม่าเสีย กับเลี้ยงหมา ๆ ที่บ้าน พอหมา ๆ ตายไปหมด ก็เริ่มมีอาการ Alzheimer หนักขึ้น มาช่วง COVID-19 … &lt;a class=&quot;more-link&quot; href=&quot;https://kitty.in.th/index.php/2025/10/25/%e0%b8%ab%e0%b8%a2%e0%b8%b5%e0%b9%88%e0%b9%81%e0%b8%9b%e0%b8%b0/&quot;&gt;Continue reading &lt;span class=&quot;screen-reader-text&quot;&gt;หยี่แปะ&lt;/span&gt; &lt;span class=&quot;meta-nav&quot;&gt;→&lt;/span&gt;&lt;/a&gt;</description>
	<pubDate>Sat, 01 Nov 2025 10:36:40 +0000</pubDate>
</item>
<item>
	<title>Kitt: Microsoft BitLocker ..</title>
	<guid>https://kitty.in.th/?p=20756</guid>
	<link>https://kitty.in.th/index.php/2025/10/29/microsoft-bitlocker/</link>
	<description>BitLocker มัน on เองจริง ๆ ด้วย … (- -)a .. ไม่ได้ logon Microsoft Account ก็โดน</description>
	<pubDate>Thu, 30 Oct 2025 07:12:55 +0000</pubDate>
</item>
<item>
	<title>Kitt: About TH Sarabun</title>
	<guid>https://kitty.in.th/?p=20677</guid>
	<link>https://kitty.in.th/index.php/2025/01/26/about-th-sarabun/</link>
	<description>เรื่องสมมติที่เกิดขึ้นจริง สิบสองปีก่อนโน้น Google Docs ยังใช้ภาษาไทยไม่ได้ดีเท่าทุกวันนี้ อจก. กับ FOSS dev หยิบมือนึง อยากเอาฟอนต์ TH Sarabun New เข้าไปอยู่ใน Google Docs จะได้สร้างเอกสารภาษาไทยได้สมบูรณ์ขึ้น โดยเฉพาะเอกสารราชการซึ่งมีมติฯ ให้ใช้ TH Sarabun PSK (อ่านต่อไปเรื่อย ๆ จะเข้าใจ PSK กับ New) และบังเอิญหยิบมือนั้นได้คุยกับ Dave Crossland คนที่ทำโครงการ Google Fonts .. เวลานั้น Dave บอก อจก. ว่ากำลังจะมาเมืองไทยพอดี ถ้าจะให้ workshop เรื่องฟอนต์ สัญญาอนุญาต การออกแบบ โปรแกรม Dave ยินดีมาก ๆ สำหรับหยิบมือนั้น การคุยกันกับ Dave เป็นการปักหมุด เรื่องฟอนต์ไทยไป … &lt;a class=&quot;more-link&quot; href=&quot;https://kitty.in.th/index.php/2025/01/26/about-th-sarabun/&quot;&gt;Continue reading &lt;span class=&quot;screen-reader-text&quot;&gt;About TH Sarabun&lt;/span&gt; &lt;span class=&quot;meta-nav&quot;&gt;→&lt;/span&gt;&lt;/a&gt;</description>
	<pubDate>Thu, 30 Oct 2025 06:53:27 +0000</pubDate>
</item>
<item>
	<title>Vee: Reasons to use Emacs in 2025</title>
	<guid>https://dev.to/veer66/reasons-to-use-emacs-in-2025-14bn</guid>
	<link>https://dev.to/veer66/reasons-to-use-emacs-in-2025-14bn</link>
	<description>&lt;p&gt;Expanding Emacs functionality is as simple as defining a new function instead of creating an entire extension package, as is often done in many other extensible editors. This function can then be re-evaluated, tested, and modified entirely within Emacs using just a few clicks or keyboard shortcuts, with no need to restart or reload Emacs. &lt;/p&gt;</description>
	<pubDate>Tue, 02 Sep 2025 15:52:03 +0000</pubDate>
</item>
<item>
	<title>Vee: Reasons to use Common Lisp in 2025</title>
	<guid>https://dev.to/veer66/reasons-to-use-common-lisp-in-2025-523h</guid>
	<link>https://dev.to/veer66/reasons-to-use-common-lisp-in-2025-523h</link>
	<description>&lt;h1&gt;
  
  
  Reasons to use Common Lisp
&lt;/h1&gt;

&lt;h2&gt;
  
  
  An actively-maintained-implementation, long-term-stable-specification programming language
&lt;/h2&gt;

&lt;p&gt;There are many programming languages that don't change much, including&lt;br /&gt;
Common Lisp, but Common Lisp implementations continue to be developed.&lt;br /&gt;
For example, SBCL (Steel Bank Common Lisp) released its latest version&lt;br /&gt;
just last month.&lt;/p&gt;

&lt;p&gt;Common Lisp can be extended through libraries. For example, cl-interpol&lt;br /&gt;
enables Perl-style strings to Common Lisp without requiring a new&lt;br /&gt;
version of Common Lisp. cl-arrows allows Common Lisp to create pipelines&lt;br /&gt;
using Clojure-style syntax without needing to update the Common Lisp&lt;br /&gt;
specification. This exceptional extensibility stems from macro and&lt;br /&gt;
particularly reader macro support in Common Lisp.&lt;/p&gt;
&lt;h2&gt;
  
  
  Feature-packed
&lt;/h2&gt;

&lt;p&gt;Common Lisp includes many features found in modern programming&lt;br /&gt;
languages, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Garbage collection&lt;/li&gt;
&lt;li&gt;Built-in data structures (e.g., vectors, hash tables)&lt;/li&gt;
&lt;li&gt;Type hints&lt;/li&gt;
&lt;li&gt;Class definitions&lt;/li&gt;
&lt;li&gt;A syntactic structure similar to list comprehensions&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Multi-paradigm
&lt;/h2&gt;

&lt;p&gt;While Lisp is commonly associated with functional programming, Common&lt;br /&gt;
Lisp doesn't enforce this paradigm. It fully supports imperative&lt;br /&gt;
programming (like Pascal), and its object-oriented programming system&lt;br /&gt;
even includes advanced features. Best of all, you can freely mix all&lt;br /&gt;
these styles. Common Lisp even embraces goto-like code via TAGBODY-GO.&lt;/p&gt;
&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Common Lisp has many implementations, and some of them, such as SBCL,&lt;br /&gt;
are compilers that can generate efficient code.&lt;/p&gt;

&lt;p&gt;With some (of course, not all) implementations, many programs written in&lt;br /&gt;
dynamic programming languages run slower than those in static ones, such&lt;br /&gt;
as C and Modula-2.&lt;/p&gt;

&lt;p&gt;First, an example of the generated assembly will be shown, along with&lt;br /&gt;
more explanation about why it might be slowed down by some dynamic&lt;br /&gt;
implementations&lt;/p&gt;

&lt;p&gt;The code listing below is a part of a program written in Modula-2, which&lt;br /&gt;
must be easy to read by programmers of languages in the extended ALGOL&lt;br /&gt;
family.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;    TYPE
      Book = RECORD
        title: ARRAY[1..64] OF CHAR;
        price: REAL;
      END;

    PROCEDURE SumPrice(a, b: Book): REAL;
    BEGIN
      RETURN a.price + b.price;
    END SumPrice;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is mainly for summing the price of books, and only the part&lt;br /&gt;
'a.price + b.price' will be focused on.&lt;/p&gt;

&lt;p&gt;'a.price + b.price' is translated into X86-64 assembly code list below&lt;br /&gt;
using the GNU Modula-2 compiler.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;    movsd   80(%rbp), %xmm1
    movsd   152(%rbp), %xmm0
    addsd   %xmm1, %xmm0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&quot;movsd 80(%rbp), %xmm1' and 'movsd 152(%rbp), %xmm0' are for loading&lt;br /&gt;
'prices' to registers '%xmm1' and '%xmm0', respectively. Finally, 'addsd&lt;br /&gt;
%xmm1, %xmm0' is for adding prices together. As can be seen, the prices&lt;br /&gt;
are loaded from exact locations relative to the value of the '%rbp'&lt;br /&gt;
register, which is one of the most efficient ways to load data from&lt;br /&gt;
memory. The instruction 'addsd' is used because prices in this program&lt;br /&gt;
are REAL (floating point numbers), and '%xmm0', '%xmm1', and 'movsd' are&lt;br /&gt;
used for the same reason. This generated code should be reasonably&lt;br /&gt;
efficient. However, the compiler needs to know the type and location of&lt;br /&gt;
the prices beforehand to choose the proper instructions and registers to&lt;br /&gt;
use.&lt;/p&gt;

&lt;p&gt;In dynamic languages, 'SumPrice' can be applied to a price whose type is&lt;br /&gt;
an INTEGER instead of a REAL, or it can even be a string/text. A&lt;br /&gt;
straightforward implementation would check the type of 'a' and 'b' at&lt;br /&gt;
runtime, which makes the program much less efficient. The checking and&lt;br /&gt;
especially branching can cost more time than adding the numbers&lt;br /&gt;
themselves. Moreover, obtaining the value of the price attribute from&lt;br /&gt;
'a' and 'b' might be done by accessing a hash table instead of directly&lt;br /&gt;
loading the value from memory. Of course, while a hash-table has many&lt;br /&gt;
advantages, it's less efficient because it requires many steps,&lt;br /&gt;
including comparing the attribute name and generating a hash value.&lt;/p&gt;

&lt;p&gt;However, compilers for dynamic languages can be much more advanced than&lt;br /&gt;
what's mentioned above, and SBCL is one such advanced compiler. SBCL can&lt;br /&gt;
infer types from the code, especially from literals. Moreover, with&lt;br /&gt;
information from type hints and 'struct' usage, SBCL can generate code&lt;br /&gt;
that's comparably as efficient as static language compilers.&lt;/p&gt;

&lt;p&gt;Given, the Common Lisp code listing below:&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight common_lisp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;defstruct&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;book&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;title&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;price&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:type&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double-float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;declaim&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;ftype&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;book&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double-float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;add-price&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;optimize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;debug&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;safety&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;add-price&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;book-price&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;book-price&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SBCL can generate assembly code for '(+ (book-price a) (book-price b))'&lt;br /&gt;
as shown below:&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;    ; 86:       F20F104A0D       MOVSD XMM1, [RDX+13]
    ; 8B:       F20F10570D       MOVSD XMM2, [RDI+13]
    ; 90:       F20F58D1         ADDSD XMM2, XMM1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The assembly code format is slightly different from the one generated by&lt;br /&gt;
the GNU Modula-2 compiler, but the main parts, the 'MOVSD' and 'ADDSD'&lt;br /&gt;
instructions and the use of XMM registers—are exactly the same. This&lt;br /&gt;
shows that we can write efficient code in Common Lisp at least for this&lt;br /&gt;
case. This shows that we can write efficient code in Common Lisp, at&lt;br /&gt;
least in this case, that is as efficient as, or nearly as efficient as,&lt;br /&gt;
a static language.&lt;/p&gt;

&lt;p&gt;This implies that Common Lisp is good both for high-level rapid&lt;br /&gt;
development and optimized code, which has two advantages: (1) in many&lt;br /&gt;
cases, there is no need to switch between two languages, i.e., a&lt;br /&gt;
high-level one and a fast one; (2) the code can be started from&lt;br /&gt;
high-level and optimized in the same code after a profiler finds&lt;br /&gt;
critical parts. This paradigm can prevent premature optimization.&lt;/p&gt;
&lt;h2&gt;
  
  
  Interactive programming
&lt;/h2&gt;

&lt;p&gt;Interactive programming may not sound familiar. However, it is a common&lt;br /&gt;
technique that has been used for decades. For example, a database engine&lt;br /&gt;
such as PostgreSQL doesn't need to be stopped and restarted just to run&lt;br /&gt;
a new SQL statement. Similarly, it is akin to a spreadsheet like Lotus&lt;br /&gt;
1-2-3 or Microsoft Excel, which can run a new formula without needing to&lt;br /&gt;
reload existing sheets or restart the program.&lt;/p&gt;

&lt;p&gt;Common Lisp is exceptionally well-suited for interactive programming&lt;br /&gt;
because of (1) integrated editors with a REPL (Read Eval Print Loop),&lt;br /&gt;
(2) the language's syntax, and (3) the active community that has&lt;br /&gt;
developed libraries specifically designed to support interactive&lt;br /&gt;
programming.&lt;/p&gt;
&lt;h3&gt;
  
  
  Integrated editors with a REPL
&lt;/h3&gt;

&lt;p&gt;With an integrated with a REPL, any part of the code can be evaluated&lt;br /&gt;
immediately without copying and pasting from an editor into a REPL. This&lt;br /&gt;
workflow provides feedback even faster than hot reloading because the&lt;br /&gt;
code can be evaluated and its results seen instantaneously, even before&lt;br /&gt;
it is saved. There are many supported editors, such as Visual Studio&lt;br /&gt;
Code, Emacs, Neovim, and others.&lt;/p&gt;
&lt;h3&gt;
  
  
  the language's syntax
&lt;/h3&gt;

&lt;p&gt;Instead of marking region arbitrarily for evaluating, which is not very&lt;br /&gt;
convenient when it is done every few seconds, in Common Lisp, we can&lt;br /&gt;
mark a form (which is similar to a block in ALGOL) by moving a cursor to&lt;br /&gt;
one of the parentheses in the code, which is very easy with structural&lt;br /&gt;
editing, which will be discussed in the next section.&lt;/p&gt;

&lt;p&gt;Moreover, even a method definition can be evaluated immediately without&lt;br /&gt;
resetting the state of the object in Common Lisp. Since method&lt;br /&gt;
definitions are not nested in defclass, this allows mixing interactive&lt;br /&gt;
programming and object-oriented programming (OOP) smoothly.&lt;/p&gt;

&lt;p&gt;Here's the corrected code listing:&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight common_lisp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;defclass&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;toto&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:initarg&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:i&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:accesor&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;defmethod&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;update-i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;toto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;setf&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the code listing above, the method 'update-i' can be&lt;br /&gt;
redefined without interfering with the pre-existing value of 'i'.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structural editing
&lt;/h2&gt;

&lt;p&gt;Instead of editing Lisp code like normal text, tree-based operations can&lt;br /&gt;
be used instead, such as paredit-join-sexps and&lt;br /&gt;
paredit-forward-slurp-sexp. Moving cursor operations, such as&lt;br /&gt;
paredit-forward, which moves the cursor to the end of the form (a&lt;br /&gt;
block). These structural moving operations are also useful for selecting&lt;br /&gt;
regions to be evaluated in a REPL.&lt;/p&gt;

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

&lt;p&gt;In brief, Common Lisp has unparalleled combined advantages, which are&lt;br /&gt;
relevant to software development especially now, not just an archaic&lt;br /&gt;
technology that just came earlier. For example, Forth has a&lt;br /&gt;
long-term-stable specification, and works well with interactive&lt;br /&gt;
programming, but it is not designed for defining classes and adding type&lt;br /&gt;
hints. Julia has similar performance optimization and OOP is even&lt;br /&gt;
richer, but it doesn't have a long-term-stable specification. Moreover,&lt;br /&gt;
Common Lisp's community is still active, as libraries, apps, and even&lt;br /&gt;
implementations continue to receive updates.&lt;/p&gt;</description>
	<pubDate>Sun, 17 Aug 2025 16:14:26 +0000</pubDate>
</item>
<item>
	<title>Thep: Tai Tham Updated, Thai Noi Revisited</title>
	<guid>tag:blogger.com,1999:blog-6815053.post-4907345211215356883</guid>
	<link>http://thep.blogspot.com/2025/07/tai-tham-updated-thai-noi-revisited.html</link>
	<description>&lt;p&gt;Update งานอักษรอีสาน&lt;/p&gt;

&lt;h4&gt;Khottabun กับอักษรธรรมแบบไร้ USE&lt;/h4&gt;

&lt;p&gt;หลังจากการวิเคราะห์ทางเลือกต่างๆ สำหรับอักษรธรรมไป 2 blog (&lt;a href=&quot;http://thep.blogspot.com/2025/04/lao-tham-font-vs-use.html&quot;&gt;Lao Tham Font vs USE&lt;/a&gt; และ &lt;a href=&quot;http://thep.blogspot.com/2025/04/to-use-or-not-to-use-for-lao-tham.html&quot;&gt;To USE or Not to USE for Lao Tham&lt;/a&gt;) และได้ตัดสินใจ &lt;strong&gt;หลีกเลี่ยง USE&lt;/strong&gt; โดยยอมทิ้ง MS Word ไว้ข้างหลัง ก็ได้ implement ใน &lt;a href=&quot;https://github.com/thep/fonts-khottabun&quot;&gt;fonts-khottabun&lt;/a&gt; ตามนั้น ตั้งแต่ &lt;a href=&quot;https://github.com/thep/fonts-khottabun/commit/a0389bd54ec668e4660513f0050b2fa96df5a43b&quot;&gt;commit a0389bd&lt;/a&gt; จนถึง &lt;a href=&quot;https://github.com/thep/fonts-khottabun/commit/1c73c80c367d8f090715064a3477a0da8a41b60d&quot;&gt;commit 1c73c80&lt;/a&gt; โดยปรับ major version ของฟอนต์ขึ้นเป็นรุ่น &lt;code&gt;003&lt;/code&gt; สำหรับอักษรธรรมแบบไม่ใช้ USE&lt;/p&gt;

&lt;h4&gt;Keyboard Layout อักษรธรรมบน Windows&lt;/h4&gt;

&lt;p&gt;ถัดมาคือ &lt;a href=&quot;https://github.com/thep/lanxang/commit/b56db0055acbedac64d43b5dc0529fe4dbb3af98&quot;&gt;ผังแป้นพิมพ์อักษรธรรมบน Windows&lt;/a&gt; ในรูปของซอร์ส KLC สำหรับสร้างเป็นผังแป้นพิมพ์ด้วย Microsoft Keyboard Layout Creator (MSKLC) 1.4 ซึ่งจะ build เป็น DLL พร้อมโปรแกรม setup&lt;/p&gt;

&lt;p&gt;ประเด็นปลีกย่อยของผังนี้คือ Windows กำหนดให้ผังแป้นพิมพ์ต้องผูกติดกับโลแคล (locale) ซึ่งกำหนดด้วยภาษาและดินแดน ตรงนี้เป็นปัญหาโดยนิยามอยู่ เพราะอักษรธรรมสามารถใช้เขียนได้หลายภาษา ไม่ว่าจะไทย ลาว ไทลื้อ ไทขึน หรือคาถาบาลี-สันสกฤต แต่ Windows จะบังคับให้เราเลือกเพียงภาษาเดียวมาประกอบกับดินแดนที่เป็นถิ่นของภาษาที่ใช้ โดยห้ามใช้ซ้ำกับผังอื่นในโลแคลนั้นๆ ด้วย ประเด็นคือ:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt; โลแคลต่างๆ มักมีผังแป้นพิมพ์อยู่แล้ว ถ้าไม่ต้องการซ้ำก็ต้องสร้างโลแคลใหม่สำหรับอักษรธรรม แต่จะกำหนดโลแคลด้วยภาษาอะไร ในเมื่ออักษรธรรมสามารถใช้เขียนได้หลายภาษา? &lt;/li&gt;
  &lt;li&gt; สมมุติว่าเราเลือกสร้างโลแคลภาษาลาวถิ่นไทย (&lt;code&gt;lo-TH&lt;/code&gt;) ด้วย Microsoft Locale Builder แต่ปัญหาคือ เราไม่สามารถเลือกบล็อคยูนิโคดของอักษรธรรมให้กับโลแคลใหม่นี้ได้ เนื่องจาก Microsoft กำหนดตัวเลข enum ให้กับบล็อคยูนิโคดต่างๆ แต่ยังไม่ได้กำหนดเลขสำหรับอ้างให้กับบล็อคอักษรธรรม! &lt;/li&gt;
  &lt;li&gt; ในเมื่อสร้างโลแคลเองไม่ได้ วิธีแก้ขัดจึงเป็นการเลือกโลแคลอะไรก็ได้ที่ไม่ซ้ำกับชุดผังแป้นพิมพ์ที่เราใช้ เช่น ใช้ th, en ไม่ได้ เพราะจะซ้ำกับสองผังหลักที่เราใช้ และผมก็จิ้มเอาโลแคลมลยาฬัมในอินเดีย (&lt;code&gt;ml-IN&lt;/code&gt;) โดยไม่มีเหตุผลใดๆ มากไปกว่าการแก้ขัด เวลาจะป้อนอักษรธรรมบน Windows ผู้ใช้ก็สลับแป้นพิมพ์ไปที่ภาษามลยาฬัม &lt;/li&gt;
  &lt;li&gt; อันที่จริง สิ่งที่เราต้องการมากกว่าในกรณีนี้คือการอ้างถึง &lt;q&gt;อักษร&lt;/q&gt; (script) ตรงๆ ไปเลย แต่การออกแบบของ Windows ยังไม่เอื้อขนาดนั้น &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;อย่างไรก็ดี เราก็ได้ผังแป้นพิมพ์อักษรธรรมที่ทำงานได้บน Windows โดยเป็นเพียงผังปุ่มจริงๆ ยังไม่มีการตรวจหรือสลับลำดับอะไร ผู้ใช้ต้องป้อนตามลำดับยูนิโคดเป๊ะๆ เช่น ᨸᩮᩢ᩠ᨶ (เป็น) ก็ต้องป้อนเป็น ป + เอ + ไม้ซัด + SAKOT + น&lt;/p&gt;

&lt;h4&gt;อักษรไทยน้อย&lt;/h4&gt;

&lt;p&gt;แม้อักษรไทยน้อยจะเรียบง่ายกว่าอักษรธรรม แต่กลับมีรายละเอียดปลีกย่อยมากกว่า ทั้งเรื่องความหลากหลายของชุดอักษรที่ใช้ การควบอักษรติดกัน การยืมตัวห้อยตัวเฟื้องจากอักษรธรรมตามแต่ผู้จารึกจะเลือกใช้ ดังที่ผมได้เคย &lt;a href=&quot;https://linux.thai.net/~thep/esaan-scripts/tn-issues/tn-encoding.html&quot;&gt;สรุปประเด็น&lt;/a&gt; ไว้ โดยยังไม่ตกลงว่าจะเลือก implement แบบไหน&lt;/p&gt;

&lt;p&gt;เมื่อหลายปีก่อน ในระหว่างที่ทำไปศึกษาไปนั้น ผมเลือกที่จะเติมอักขระลงในช่องที่ยังว่างอยู่ของบล็อคยูนิโคดอักษรลาว ไม่ว่าจะเป็นตัวเฟื้องหรือตัวควบต่างๆ แต่ยิ่งพบอักขระที่ต้องเพิ่มรหัสมากขึ้นจากการอ่านจารึก ก็ยิ่งเห็นว่ามันไม่ใช่วิธีที่ดีในระยะยาว&lt;/p&gt;

&lt;p&gt;ตอนนี้ได้โอกาสมาปัดฝุ่น โดยบล็อคยูนิโคดลาวเองก็มีมีการเพิ่มอักขระสำหรับเขียนภาษาบาลีตามแบบพุทธบัณฑิตสภา จึงได้พิจารณาทางเลือกต่างๆ ใหม่&lt;/p&gt;

&lt;p&gt;เริ่มจากตรวจสอบความคืบหน้าใน Unicode ของอักษรไทยน้อย ซึ่ง &lt;a href=&quot;https://scriptsource.org/cms/scripts/page.php?item_id=entry_detail&amp;amp;uid=xcwbveqs44&quot;&gt;ข้อมูลใน ScriptSource&lt;/a&gt; ของ SIL ได้บันทึกรายละเอียดไว้ โดยสถานะล่าสุดคือ &lt;strong&gt;ยังไม่กำหนดใน Unicode&lt;/strong&gt; ส่วนกระบวนการเท่าที่ผ่านมาคือ&lt;/p&gt;

&lt;dl&gt;
  &lt;dt&gt; 2018-01-02 Request to Add Thai Characters — Nitaya Kanchanawan (WG2 N4927,  &lt;a href=&quot;https://www.unicode.org/L2/L2018/18041-n4927-add-thai.pdf&quot;&gt;L2/18-041&lt;/a&gt;) &lt;/dt&gt;
      &lt;dd&gt; เป็นข้อเสนอขอเพิ่มอักขระไทยน้อยลงในบล็อค&lt;em&gt;อักษรไทย!&lt;/em&gt; โดยเป็นงานที่เกี่ยวเนื่องกับการกำหนดมาตรฐานการถอดอักษรไทยน้อยเป็นอักษรโรมันที่ราชบัณฑิตยสภาได้เสนอเข้าสู่ ISO/IEC โดยได้รับความเห็นว่าควรกำหนดรหัสอักขระก่อน แต่ไม่ทราบว่าด้วยเหตุผลใด ราชบัณฑิตยสภาถึงได้เสนอให้เพิ่มอักขระในบล็อคอักษรไทยแทนที่จะเป็นบล็อคอักษรลาวที่อยู่ในสายวิวัฒนาการโดยตรง &lt;/dd&gt;

  &lt;dt&gt; 2018-01-19 Information and documentation - Transliteration of scripts in use in Thailand - Part 1: Transliteration of Akson-Thai-Noi — TC46 / WG3 (WG2 N4927A, L2/18-042) &lt;/dt&gt;
       &lt;dd&gt; เป็นร่างมาตรฐานการถอดอักษรไทยน้อยเป็นอักษรโรมันที่เป็นต้นเรื่อง ตัวเอกสารต้องใช้รหัสผ่านในการเข้าถึง และไม่เกี่ยวข้องกับเรื่องรหัสอักขระโดยตรง ผมจึงไม่ใส่ลิงก์ไว้ &lt;/dd&gt;

  &lt;dt&gt; 2018-01-19 Results on ISO CD 20674-1: Information and documentation - Transliteration of scripts in use in Thailand - Part 1: Transliteration of Akson-Thai-Noi — TC46 Secretatriat (WG2 N4927B, &lt;a href=&quot;https://www.unicode.org/L2/L2018/18043-n4927b-iso-tc046-n2654-results.pdf&quot;&gt;L2/18-043&lt;/a&gt;) &lt;/dt&gt;
       &lt;dd&gt; ผลการโหวตร่างมาตรฐานการถอดอักษรไทยน้อยของคณะกรรมการ เห็นชอบ 16, เห็นชอบโดยมีข้อคิดเห็น 2, ไม่เห็นชอบ 1, งดออกเสียง 19 &lt;/dd&gt;

  &lt;dt&gt; 2018-02-20 Thai-Noi Transliteration — Martin Hosken (WG2 N4939, &lt;a href=&quot;https://www.unicode.org/L2/L2018/18068-n4939-thai-noi-translit.pdf&quot;&gt;L2/18-068&lt;/a&gt;) &lt;/dt&gt;
       &lt;dd&gt; เป็นความเห็นจากคุณ Martin Hosken ผู้เชี่ยวชาญจาก SIL โดยสรุปเห็นว่าอักษรไทยน้อยเข้ากันได้กับอักษรธรรมมากกว่าอักษรไทย &lt;/dd&gt;

  &lt;dt&gt; 2018-02-28 Towards a comprehensive proposal for Thai Noi / Lao Buhan script — Ben Mitchell (&lt;a href=&quot;https://www.unicode.org/L2/L2018/18072-toward-thai-noi.pdf&quot;&gt;L2/18-072&lt;/a&gt;) &lt;/dt&gt;
       &lt;dd&gt; เป็นความเห็นจากคุณ Ben Mitchell ผู้เชี่ยวชาญอีกท่านหนึ่ง โดยมีผู้ร่วมให้ข้อมูลคือ Patrick Chew, ผมเอง และ อ.ประพันธ์ เอี่ยมวิริยะกุล โดยสรุปเห็นว่าควรเพิ่มอักขระไทยน้อยในบล็อคอักษรลาว โดยเพิ่มเติมจากอักษรลาวบาลีของพุทธบัณฑิตสภาอีกที และได้เสนอทางเลือกต่างๆ ดังที่ผมได้สรุปไว้ แต่ยังไม่ระบุว่าจะเลือกวิธีการไหน &lt;/dd&gt;

  &lt;dt&gt; Recommendations to UTC #155 April-May 2018 on Script Proposals (&lt;a href=&quot;https://www.unicode.org/L2/L2018/18168-script-rec.pdf&quot;&gt;L2/18-168&lt;/a&gt;) (อยู่ที่ข้อ 6.) และบันทึกการประชุมของ UTC #155 (&lt;a href=&quot;https://www.unicode.org/L2/L2018/18115.htm&quot;&gt;L2/18-115&lt;/a&gt;) (อยู่ที่ข้อ D.8.1 และ D.8.3) &lt;/dt&gt;
       &lt;dd&gt; สรุปข้อแนะนำของคณะกรรมการว่าอักษรไทยน้อยไม่ใข่ส่วนขยายของอักษรไทย และผู้เสนอร่างอักษรไทยน้อย (หมายถึง อ.นิตยา กาญจนวรรณ จากราชบัณฑิตยสภา) ควรนำข้อมูลในเอกสารของคุณ Ben Mitchell ข้างต้นไปใช้ประกอบการร่างด้วย โดยมอบให้ Deborah Anderson ร่างเอกสารแจ้งเจ้าของร่าง ซึ่งก็คือเอกสาร &lt;a href=&quot;https://www.unicode.org/L2/L2018/18070-feedback-thai-cd.pdf&quot;&gt;L2/18-070&lt;/a&gt; &lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;แล้วกระบวนการทั้งหมดก็หยุดอยู่ที่รอการดำเนินการของราชบัณฑิตยสภาต่อจากนั้น&lt;/p&gt;

&lt;p&gt;สรุปว่ายังไม่มีมาตรฐาน Unicode อักษรไทยน้อยเกิดขึ้น ถ้าจะ implement ตอนนี้ก็เป็นเพียงตุ๊กตาเท่านั้น&lt;/p&gt;

&lt;p&gt;จากทางเลือกต่างๆ ที่มี ผมพิจารณาเลือกเองไปก่อนอย่างนี้:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt; &lt;strong&gt;Conjunct&lt;/strong&gt; หรือการสังโยคพยัญชนะด้วยตัวห้อย/ตัวเฟื้อง ใช้พินทุ (U+0EBA LAO SIGN PALI VIRAMA) ตามด้วยพยัญชนะที่จะสังโยค ยกเว้นกรณีที่มีรหัสอยู่แล้ว คือ ล ห้อย (U+0EBC) และ ย เฟื้อง (U+0EBD) ก็ใช้รหัสนั้นๆ ไปเลย &lt;/li&gt;
  &lt;li&gt; &lt;strong&gt;Ligature&lt;/strong&gt; หรือตัวแฝด หรืออักษรควบ ใช้ U+200D ZERO WIDTH JOINER (ZWJ) เชื่อมพยัญชนะ ยกเว้นกรณีที่มีรหัสอยู่แล้ว คือ U+0EDC (ໜ), U+0EDD (ໝ) ก็ใช้รหัสนั้นๆ ไปเลย &lt;/li&gt;
  &lt;li&gt; &lt;strong&gt;สระออย&lt;/strong&gt; กำหนดอักขระใหม่ในช่องที่ยังว่างอยู่ คือ U+0EBE เพื่อให้เป็นวิธีที่สอดคล้องกับอักษรธรรม (อีกวิธีที่ไม่ต้องกำหนดอักขระใหม่คือใช้ พินทุ + ຢ แต่จะเป็นวิธีที่แปลกแยกจากอักษรธรรม) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;เมื่อเลือกวิธีนี้แล้ว ก็ปรับเปลี่ยนทั้งในฟอนต์ Khottabun และในระบบป้อนข้อความ Lanxang ดังนี้:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt; &lt;code&gt;fonts-khottabun&lt;/code&gt;: detach glyph ตัวห้อย/ตัวเฟื้องและตัวควบทั้งหมดจากรหัสอักขระ แล้วสร้างกฎ &lt;code&gt;'ccmp' TN conjuncts&lt;/code&gt; และ &lt;code&gt;'ccmp' TN subjoins&lt;/code&gt; เพื่อเข้าถึง glyph เหล่านี้ผ่านพินทุและ ZWJ ตามลำดับ พร้อมกับปรับรุ่น major ของฟอนต์เป็นรุ่น &lt;code&gt;004&lt;/code&gt; (&lt;a href=&quot;https://github.com/thep/fonts-khottabun/commit/cc49e5a7e2b77925c4fee58314c6c9d124e476ed&quot;&gt;commit cc4935a&lt;/a&gt;) &lt;/li&gt;
  &lt;li&gt; &lt;code&gt;lanxang&lt;/code&gt;: ตัดกระบวนการแปลง &lt;q&gt;พินทุ + พยัญชนะ&lt;/q&gt; เป็นอักขระตัวห้อย/ตัวเฟื้อง และ &lt;q&gt;พยัญชนะ + ZWJ + พยัญชนะ&lt;/q&gt; เป็นอักขระตัวควบ ทั้งหมด (ทิ้ง sequence ประกอบไว้อย่างนั้นในข้อความเลย แล้วให้ฟอนต์จัดการตอน render) ยกเว้นการควบ ໜ,ໝ เพื่ออำนวยความสะดวก (&lt;a href=&quot;https://github.com/thep/lanxang/commit/f0645b1e7aa0bcc57f495551883e6955cab59c60&quot;&gt;commit f0645b1&lt;/a&gt;) แต่ก็ยังป้อน ໜ, ໝ โดยตรงได้ด้วย level 3 เช่นกัน &lt;/li&gt;
  &lt;li&gt; &lt;code&gt;lanxang&lt;/code&gt;: เพิ่มผังแป้นพิมพ์อักษรไทยน้อยสำหรับ Windows ด้วย (&lt;a href=&quot;https://github.com/thep/lanxang/commit/cce81cdbf7f23382a33db9de8d7a6919dfecb2ee&quot;&gt;commit cce81cd&lt;/a&gt;) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;พร้อมกันนี้ก็แปลงวิธีลงรหัสอักขระไทยน้อยในตัวอย่างการปริวรรตทั้งหลายด้วย (&lt;a href=&quot;https://linux.thai.net/~thep/esaan-scripts/trans-tn/khankhak.html&quot;&gt;พญาคันคาก&lt;/a&gt;, &lt;a href=&quot;https://linux.thai.net/~thep/esaan-scripts/trans-tn/heetkhong.html&quot;&gt;ฮีตคองคะลำ&lt;/a&gt;, &lt;a href=&quot;https://linux.thai.net/~thep/esaan-scripts/trans-tn/phayanak.html&quot;&gt;บูชาพญานาค&lt;/a&gt;, &lt;a href=&quot;https://linux.thai.net/~thep/esaan-scripts/trans-tn/nokkrajork.html&quot;&gt;นกกระจอก&lt;/a&gt;)&lt;/p&gt;</description>
	<pubDate>Fri, 25 Jul 2025 09:46:00 +0000</pubDate>
	<author>noreply@blogger.com (Thep)</author>
</item>
<item>
	<title>Vee: My programming environment journey</title>
	<guid>https://dev.to/veer66/my-programming-environment-journey-5748</guid>
	<link>https://dev.to/veer66/my-programming-environment-journey-5748</link>
	<description>&lt;p&gt;No one actually cares about my programming environment journey, but I’ve often been asked to share it, perhaps for the sake of social media algorithms. I post it here, so later, I can copy and paste this conveniently.&lt;/p&gt;

&lt;p&gt;My first computer, in the sense that I, not someone else, made the decision to buy it, ran Debian in 2002. It was a used Compaq desktop with a Pentium II processor, which I bought from Zeer Rangsit, a used computer market that may be the most famous in Thailand these days. When I got it home, I installed Debian right away. Before I bought my computer, I had used MBasic, mainly MS-DOS, Windows 3.1 (though rarely), and  Solaris (remotely).  For experimentation, I used Xenix, AIX, and one on DEC PDP-11 that I forgot.&lt;/p&gt;

&lt;p&gt;Since I started with MBasic, that was my first programming environment. I learned Logo at a summer camp, so that became my second. Later, my father bought me a copy of Turbo Basic, and at school, I switched to Turbo Pascal.&lt;/p&gt;

&lt;p&gt;After moving to GNU/Linux, I used more editors instead IDEs. From 1995 to 2010, my editors were pico, nvi, vim, TextMate, and Emacs paired with GCC (mostly C, not C++), PHP, Perl, Ruby, Python, JavaScript, and SQL. I also used VisualAge to learn Java in the 90s. I tried Haskell, OCaml, Objective C, Lua, Julia, and Scala too, but it was strictly for learning only.&lt;/p&gt;

&lt;p&gt;After 2010, I used IntelliJ IDEA and Eclipse for Java and Kotlin. For Rust (instead of C), I used Emacs and Visual Studio Code. I explored Racket for learning purposes, then later started coding seriously in Clojure and Common Lisp. I tried using Vim 9.x and Neovim too, they were great, but not quite my cup of tea.&lt;/p&gt;

&lt;p&gt;In 2025, a few days ago, I learned Smalltalk with Pharo to deepen my understanding of OOP and exploratory programming.&lt;/p&gt;

&lt;p&gt;Update 2025/07/20: I forgot to mention xBase. In the '90s, I used it in a programming competition, but none of my programs in xBase reach production.&lt;/p&gt;</description>
	<pubDate>Sat, 19 Jul 2025 04:58:58 +0000</pubDate>
</item>
<item>
	<title>Kitt: All photos here are AI-generated.</title>
	<guid>https://kitty.in.th/?p=20742</guid>
	<link>https://kitty.in.th/index.php/2025/05/18/all-photos-here-are-ai-generated/</link>
	<description>How convincing they are ..</description>
	<pubDate>Sun, 08 Jun 2025 07:10:31 +0000</pubDate>
</item>
<item>
	<title>Kitt: I use Arch btw ..</title>
	<guid>https://kitty.in.th/?p=20739</guid>
	<link>https://kitty.in.th/index.php/2025/06/08/i-use-arch-btw/</link>
	<pubDate>Sun, 08 Jun 2025 06:42:54 +0000</pubDate>
</item>
<item>
	<title>Kitt: วันสงกรานต์ พ.ศ. 2568</title>
	<guid>https://kitty.in.th/?p=20735</guid>
	<link>https://kitty.in.th/index.php/2025/04/13/%e0%b8%a7%e0%b8%b1%e0%b8%99%e0%b8%aa%e0%b8%87%e0%b8%81%e0%b8%a3%e0%b8%b2%e0%b8%99%e0%b8%95%e0%b9%8c-%e0%b8%9e-%e0%b8%a8-2568/</link>
	<description>วันสงกรานต์ปี 2568 เป็นปี จ.ศ. (2568 – 1181) = 1387 วันเถลิงศก ตรงกับ(1387 * 0.2587)+ floor(1387 / 100 + 0.38)– floor(1387 / 4 + 0.5)– floor(1387 / 400 + 0.595)– 5.53375= 358.88625 + 14 – 347 – 4 – 5.53375= 16.3525= วันที่ 16 เมษายน 2568 เวลา 08:27:36 วันสงกรานต์ ตรงกับ16.3525 – 2.165 = 14.1875= วันที่ 14 เมษายน 2568 … &lt;a class=&quot;more-link&quot; href=&quot;https://kitty.in.th/index.php/2025/04/13/%e0%b8%a7%e0%b8%b1%e0%b8%99%e0%b8%aa%e0%b8%87%e0%b8%81%e0%b8%a3%e0%b8%b2%e0%b8%99%e0%b8%95%e0%b9%8c-%e0%b8%9e-%e0%b8%a8-2568/&quot;&gt;Continue reading &lt;span class=&quot;screen-reader-text&quot;&gt;วันสงกรานต์ พ.ศ. 2568&lt;/span&gt; &lt;span class=&quot;meta-nav&quot;&gt;→&lt;/span&gt;&lt;/a&gt;</description>
	<pubDate>Sun, 13 Apr 2025 04:08:11 +0000</pubDate>
</item>
<item>
	<title>Thep: To USE or Not to USE for Lao Tham</title>
	<guid>tag:blogger.com,1999:blog-6815053.post-4138930758616323261</guid>
	<link>http://thep.blogspot.com/2025/04/to-use-or-not-to-use-for-lao-tham.html</link>
	<description>&lt;p&gt;จาก &lt;a href=&quot;http://thep.blogspot.com/2025/04/lao-tham-font-vs-use.html&quot;&gt;blog ที่แล้ว&lt;/a&gt; ผมได้เล่าถึงการรองรับอักษรธรรมในปัจจุบันที่ text shaping engine ต่างๆ หันมาใช้ Universal Shaping Engine (USE) ตามข้อกำหนดของไมโครซอฟท์ โดย USE เองเป็น engine ครอบจักรวาลที่มีการจัดการภายในตามคุณสมบัติของอักขระ Unicode เช่น การสลับสระหน้ากับพยัญชนะต้นสำหรับอักษรตระกูลพราหมี และเรียกใช้ OpenType feature ต่างๆ ในฟอนต์ตามลำดับที่กำหนดไว้&lt;/p&gt;

&lt;p&gt;และการจัดการภายในของ USE ก็ทำให้มีข้อเสนอที่จะปรับโครงสร้างการลงรหัสข้อความอักษรธรรมเพื่อให้ทำงานกับ USE ได้ แต่มันก็ยังไม่เข้าที่เข้าทางนัก จึงเกิดแนวคิดที่จะหลบเลี่ยง USE แล้วทำทุกอย่างเองในฟอนต์ แต่ไปติดปัญหาที่ MS Word ที่ไม่ยอมให้หลบได้ง่ายๆ ทำให้เราอยู่บนทางแยกที่ต้องเลือกว่าจะใช้ USE ที่ยังไม่เข้าที่ หรือจะเลี่ยง USE ไปทำทุกอย่างเองโดยทิ้ง MS Word ไว้ข้างหลัง&lt;/p&gt;

&lt;p&gt;blog นี้ก็จะวิเคราะห์ต่อ ว่าทางเลือกแต่ละทางมีข้อดีข้อเสียอย่างไร&lt;/p&gt;

&lt;h4&gt;Encoding แบบใหม่&lt;/h4&gt;

&lt;p&gt;ตามข้อเสนอในเอกสาร &lt;a href=&quot;https://www.unicode.org/L2/L2019/19365-tai-tham-structure.pdf&quot;&gt;Structuring Tai Tham Unicode&lt;/a&gt; เมื่อตัดรายละเอียดที่อักษรธรรมลาว/อีสานไม่ใช้ออกไป ก็พอจะสรุปลำดับอักขระในข้อความได้เป็น:&lt;/p&gt;

&lt;pre&gt;  S ::= CC (V&lt;sub&gt;s&lt;/sub&gt; | V&lt;sub&gt;f&lt;/sub&gt;)?
&lt;/pre&gt;

&lt;p&gt;โดยที่ &lt;code&gt;CC&lt;/code&gt; คือ consonant cluster พร้อมสระหน้า/ล่าง/บน วรรณยุกต์ สระหรือตัวสะกดปิดท้าย&lt;/p&gt;

&lt;pre&gt;  CC ::= C M? V? T? F?

  C ::= [&amp;lt;ก&amp;gt;-&amp;lt;ฮ&amp;gt;&amp;lt;อิลอย&amp;gt;-&amp;lt;โอลอย&amp;gt;&amp;lt;แล&amp;gt;&amp;lt;ส_สองห้อง&amp;gt;&amp;lt;ตัวเลข&amp;gt;] | &amp;lt;ห&amp;gt;&amp;lt;SAKOT&amp;gt;[&amp;lt;ก&amp;gt;-&amp;lt;ม&amp;gt;]

  M ::= &amp;lt;ระวง&amp;gt;? &amp;lt;ล_ล่าง&amp;gt;? (&amp;lt;SAKOT&amp;gt;&amp;lt;ว&amp;gt;)? (&amp;lt;SAKOT&amp;gt;&amp;lt;ย&amp;gt;)?

  V ::= V&lt;sub&gt;p&lt;/sub&gt;? V&lt;sub&gt;b&lt;/sub&gt;? V&lt;sub&gt;a&lt;/sub&gt;? 
  V&lt;sub&gt;p&lt;/sub&gt; ::= [&amp;lt;เอ&amp;gt;-&amp;lt;ไม้ม้วน&amp;gt;] &lt;em&gt;// สระหน้า&lt;/em&gt;
  V&lt;sub&gt;b&lt;/sub&gt; ::= [&amp;lt;อุ&amp;gt;-&amp;lt;อู&amp;gt;&amp;lt;ออ_ล่าง&amp;gt;] &lt;em&gt;// สระล่าง&lt;/em&gt;
  V&lt;sub&gt;a&lt;/sub&gt; ::= [&amp;lt;อิ&amp;gt;-&amp;lt;อือ&amp;gt;&amp;lt;ไม้กง&amp;gt;&amp;lt;ไม้เก๋าห่อนึ่ง&amp;gt;][&amp;lt;ไม้ซัด&amp;gt;&amp;lt;ไม้กั๋ง&amp;gt;]? &lt;em&gt;// สระบน&lt;/em&gt;

  T ::= [&amp;lt;ไม้เอก&amp;gt;-&amp;lt;ไม้โท&amp;gt;]

  F ::= F&lt;sub&gt;s&lt;/sub&gt;? [&amp;lt;ละทั้งหลาย&amp;gt;&amp;lt;ไม้กั๋งไหล&amp;gt;&amp;lt;ง_บน&amp;gt;&amp;lt;ม_ล่าง&amp;gt;&amp;lt;บ_ล่าง&amp;gt;&amp;lt;ส_ล่าง&amp;gt;&amp;lt;ไม้กั๋ง&amp;gt;]? (&amp;lt;SAKOT&amp;gt; S)?
  F&lt;sub&gt;s&lt;/sub&gt; ::= [&amp;lt;อ&amp;gt;&amp;lt;ส_สองห้อง&amp;gt;&amp;lt;ออย&amp;gt;] | &amp;lt;SAKOT&amp;gt;[&amp;lt;ก&amp;gt;-&amp;lt;ฬ&amp;gt;] &lt;em&gt;// อ ของสระเอือ หรือ ตัวสะกด&lt;/em&gt;
&lt;/pre&gt;

&lt;p&gt;สังเกตว่ามี recursion ใน &lt;code&gt;F&lt;/code&gt; เพื่อแทนลูกโซ่ของพยางค์ในคำบาลีด้วย&lt;/p&gt;

&lt;p&gt;ต่อจาก &lt;code&gt;CC&lt;/code&gt; ก็จะตามด้วยสระกินที่ (spacing vowels) ซึ่งแบ่งเป็นสระมีตัวสะกด (&lt;code&gt;V&lt;sub&gt;s&lt;/sub&gt;&lt;/code&gt;) และสระไม่มีตัวสะกด (&lt;code&gt;V&lt;sub&gt;f&lt;/sub&gt;&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;สำหรับสระมีตัวสะกด &lt;code&gt;V&lt;sub&gt;s&lt;/sub&gt;&lt;/code&gt; คือสระอาหรือสระอำ (สระอำในอักษรธรรมไม่ได้มีรหัสอักขระเฉพาะเหมือนอักษรไทย แต่แทนด้วยสระอาตามด้วยไม้กั๋ง (นิคหิต) ความจริงอาจนับไม้กั๋งเป็นตัวสะกดในสระอำก็ได้ แต่กฎนี้พยายามจัดการสระอากับสระอำไปด้วยกัน กลายเป็นว่าสระอำก็ยังมีตัวสะกดได้อีก) พร้อมตัวสะกด &lt;code&gt;F&lt;sub&gt;s&lt;/sub&gt;&lt;/code&gt; (ถ้ามี)&lt;/p&gt;

&lt;pre&gt;  V&lt;sub&gt;s&lt;/sub&gt; ::= AV F&lt;sub&gt;s&lt;/sub&gt;?
  AV ::= [&amp;lt;อา&amp;gt;&amp;lt;อาสูง&amp;gt;] &amp;lt;ไม้กั๋ง&amp;gt;? &lt;em&gt;// สระอา สระอำ&lt;/em&gt;
&lt;/pre&gt;

&lt;p&gt;ส่วนสระไม่มีตัวสะกด &lt;code&gt;V&lt;sub&gt;f&lt;/sub&gt;&lt;/code&gt; ในตัวเนื้อหาของร่างฯ ได้บรรยายถึงสระเอาะและสระเอือะ แต่ในสรุปส่วนท้ายดูจะลืมสระเอาะไป และยังจัดการ อ ของสระเอือะซ้ำซ้อนกับใน &lt;code&gt;F&lt;sub&gt;s&lt;/sub&gt;&lt;/code&gt; อีก&lt;/p&gt;

&lt;pre&gt;  V&lt;sub&gt;f&lt;/sub&gt; ::= &amp;lt;อ&amp;gt;? &amp;lt;อะ&amp;gt; &lt;em&gt;// วิสรรชนีย์ของสระเอือะ&lt;/em&gt;
&lt;/pre&gt;

&lt;h4&gt;Encoding แบบ USE&lt;/h4&gt;

&lt;p&gt;แม้ encoding แบบใหม่ที่เสนอมีจุดมุ่งหมายเพื่อให้วาดแสดงด้วย USE แต่เมื่อลองใช้กับ USE จริงกลับยังมี dotted circle เกิดขึ้นในหลายกรณี ซึ่งจากการทดลองก็พอจะสังเกตลักษณะของ USE ที่ต่างจากโครงสร้างที่เสนอในร่างดังนี้:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt; ลำดับสระใน &lt;code&gt;V&lt;/code&gt; สระบนมาก่อนสระล่าง ไม่ใช่ตามหลังสระล่างอย่างในร่างฯ ดังนั้นจึงอาจปรับกฎเป็น:
&lt;pre&gt;  V ::= V&lt;sub&gt;p&lt;/sub&gt;? V&lt;sub&gt;a&lt;/sub&gt;? V&lt;sub&gt;b&lt;/sub&gt;?
&lt;/pre&gt;
       &lt;/li&gt;
  &lt;li&gt; วรรณยุกต์อยู่หน้าสระกินที่ไม่ได้ แต่ตามหลังได้ และต้องอยู่ก่อนตัวสะกด ดูเหมือน USE จะนับ &lt;code&gt;V&lt;sub&gt;s&lt;/sub&gt;&lt;/code&gt; เป็นส่วนหนึ่งของ &lt;code&gt;V&lt;/code&gt;:
&lt;pre&gt;  V ::= V&lt;sub&gt;p&lt;/sub&gt;? V&lt;sub&gt;a&lt;/sub&gt;? V&lt;sub&gt;b&lt;/sub&gt;? V&lt;sub&gt;s&lt;/sub&gt;?
&lt;/pre&gt;
       ซึ่งถ้าเป็นเช่นนั้น ก็หมายความว่า USE ก็ยังต้องการการ reorder ให้วรรณยุกต์ไปอยู่ในตำแหน่งก่อนหน้าสระกินที่เพื่อให้สามารถซ้อนบนพยัญชนะได้ด้วย มันจะกลายเป็นความซับซ้อนเกินจำเป็นน่ะสิ &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;หลักการสำหรับการป้อนข้อความ&lt;/h4&gt;

&lt;p&gt;สมมติว่าเราใช้ encoding แบบ USE เราจะมีหลักในใจอย่างไร? เราจะใช้ลำดับการพิมพ์แบบที่เราเคยใช้กับอักษรไทยไม่ได้อีกแล้ว เพราะมันคือการ encode แบบกึ่ง visual ไม่ว่าเขาจะยืนยันที่จะเรียกว่า &lt;q&gt;logical order&lt;/q&gt; ยังไงก็ตาม แต่ลำดับการ encode นี้จะไม่ตรงกับลำดับการสะกดคำเสมอไป มันเน้นให้เรียงพิมพ์ได้เป็นหลัก! โดยมีลำดับแบบที่เรียกว่า &lt;q&gt;logical order&lt;/q&gt; มาหลอกให้งงเล่น&lt;/p&gt;

&lt;p&gt;หลักการคือ&lt;/p&gt;
&lt;ol start=&quot;0&quot;&gt;
  &lt;li&gt; ละทิ้งลำดับการสะกดในใจไว้ก่อน พิจารณารูปร่างของข้อความที่ต้องการ แล้ว encode ตามกฎในข้อถัดๆ ไป &lt;/li&gt;
  &lt;li&gt; ผสมตัวห้อย ตัวเฟื้อง หรือระวง กับพยัญชนะต้นก่อน โดยมากเป็นตัวควบกล้ำ &lt;/li&gt;
  &lt;li&gt; ตามด้วยสระ โดยถ้ามีสระหลายตัว ให้วางสระตามลำดับ หน้า, บน, ล่าง, ขวา &lt;/li&gt;
  &lt;li&gt; ตามด้วยวรรณยุกต์ &lt;/li&gt;
  &lt;li&gt; ตามด้วยตัวสะกด ซึ่งอาจเป็นตัวห้อย, ตัวเฟื้อง, ไม้กั๋ง, ง สะกดบน, หรือไม้กั๋งไหล &lt;/li&gt;
  &lt;li&gt; ถ้ามีการเชื่อมพยางค์เป็นลูกโซ่แบบบาลี ก็นับตัวสะกดเป็นพยัญชนะต้นของพยางค์ถัดไปแล้วใส่สระตามได้เลย &lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;ความไม่ปกติของลำดับ&lt;/h4&gt;

&lt;p&gt;หลักการที่ว่าไปก็ดูปกติดีนี่? แต่ความซับซ้อนของอักษรธรรมทำให้มันไม่ตรงไปตรงมาอย่างนั้น ต่อไปนี้คือกรณีต่างๆ ที่ฝืนความรู้สึก อย่างน้อยก็ในระยะแรก&lt;/p&gt;

&lt;h5&gt;การสะกดแม่กกด้วยไม้ซัด&lt;/h5&gt;

&lt;p&gt;ไม้ซัดถือว่าเป็นสระบน (&lt;code&gt;V&lt;sub&gt;a&lt;/sub&gt;&lt;/code&gt;) ในกฎ ซึ่ง encoding ในร่างฯ สามารถตามหลังสระล่าง (&lt;code&gt;V&lt;sub&gt;b&lt;/sub&gt;&lt;/code&gt;) ได้ แต่ตาม encoding ของ USE ต้องมาก่อนสระล่าง ดังนั้น เมื่อไม้ซัดทำหน้าที่เป็นตัวสะกดแม่กก จึงต้องใช้ลำดับที่ตัวสะกดมาก่อนสระ ไม่ใช่สระมาก่อนตัวสะกด&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/enc-maisat-final.png&quot; width=&quot;623&quot; /&gt;
  
&lt;/figure&gt;

&lt;p&gt;แต่ก็จะมีกรณีที่ไม่สามารถ encode ได้ ไม่ว่าจะตามร่างฯ หรือตาม USE คือเมื่อเป็นตัวสะกดของสระอา&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/enc-maisat-after-aa.png&quot; width=&quot;109&quot; /&gt;
  
&lt;/figure&gt;

&lt;p&gt;อาจจะยกเว้นคำว่า &lt;q&gt;นาค&lt;/q&gt; ที่สามารถซ่อนลำดับไว้ภายใต้รูปเขียนพิเศษได้&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/enc-maisat-naak.png&quot; width=&quot;620&quot; /&gt;
  
&lt;/figure&gt;

&lt;h5&gt;เมื่อมีตัวห้อย/ตัวเฟื้องหรือสระระหว่าง cluster&lt;/h5&gt;

&lt;p&gt;การเขียนอักษรธรรมในหลายกรณีมีการใช้ตัวห้อย/ตัวเฟื้องเป็นพยัญชนะต้นของพยางค์ถัดไป แทนที่จะใช้ตัวเต็ม ซึ่งในกรณีเหล่านี้ ถ้าวางตัวห้อย/ตัวเฟื้องในตำแหน่งของตัวสะกด ก็จะไม่สามารถวางสระต่อได้อีก เพราะดูเหมือน USE ไม่ได้รองรับ recursion ใน &lt;code&gt;F&lt;/code&gt; ตามกฎในร่างฯ และเมื่อแจงต่อไป &lt;code&gt;CC&lt;/code&gt; ของพยางค์ถัดไปก็ขาดพยัญชนะต้นตัวเต็ม (&lt;code&gt;C&lt;/code&gt;) มาขึ้นต้น &lt;code&gt;CC&lt;/code&gt; แต่ถ้า encode โดยเลี่ยงให้ตัวห้อย/ตัวเฟื้องดังกล่าวเป็นส่วนหนึ่งของ &lt;code&gt;CC&lt;/code&gt; ของพยางค์ก่อนหน้าก็จะสามารถวางสระต่อได้ แต่ลำดับก็จะดูขัดสามัญสำนึกสักหน่อย&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/enc-sub-between.png&quot; width=&quot;630&quot; /&gt;
  
&lt;/figure&gt;

&lt;p&gt;แต่ในบางกรณีก็ไม่เอื้อให้ทำเช่นนั้น เช่น เมื่อมีสระมาคั่นในแบบที่ไม่สามารถสลับลำดับได้&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/enc-sub-noenc.png&quot; width=&quot;160&quot; /&gt;
  
&lt;/figure&gt;

&lt;h5&gt;ในคำย่อที่มีการยืมพยัญชนะต้น&lt;/h5&gt;

&lt;p&gt;บ่อยครั้งที่อักษรธรรมมีการใช้รูปเขียนย่อในลักษณะที่ใช้พยัญชนะต้นตัวเดียวซ้ำในพยางค์มากกว่าหนึ่งพยางค์ ในจำนวนนั้น บางคำอาจสามารถยังจัดลำดับอักขระจนเข้ากับกฎเกณฑ์ของ USE ได้ แม้จะดูเหมือนการเปลี่ยนหน้าที่อักขระ เช่น เปลี่ยนตัวสะกดมาเป็นตัวควบ หรืออาจมีการสลับลำดับสระของพยางค์ต่างๆ&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/enc-compact-ok.png&quot; width=&quot;632&quot; /&gt;
  
&lt;/figure&gt;

&lt;p&gt;แต่บางกรณีก็ไม่สามารถจัดลำดับให้เข้าเกณฑ์ได้&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/enc-compact-not-ok.png&quot; width=&quot;155&quot; /&gt;
  
&lt;/figure&gt;

&lt;h4&gt;วิธีหลบเลี่ยง?&lt;/h4&gt;

&lt;p&gt;อย่างไรก็ดี ปัญหาทั้งหมดนี้สามารถหลบเลี่ยงได้ โดยลบ glyph DOTTED CIRCLE (&lt;code&gt;uni25CC&lt;/code&gt;) ออกจากฟอนต์เสีย แล้ว USE ก็จะไม่แสดง dotted circle อีกเลย!&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/enc-nodot.png&quot; width=&quot;159&quot; /&gt;
  
&lt;/figure&gt;

&lt;p&gt;ที่กล่าวมาทั้งหมดนี้คือการทดสอบกับแอปที่ใช้ Harfbuzz แต่สุดท้าย เมื่อนำไปทดสอบกับ MS Word ปรากฏว่ามันก็ยังไม่ยอมง่ายๆ อยู่ดี โดยปัญหาหลักที่พบมีสองข้อ ข้อแรกคือกฎของตัวห้อย/ตัวเฟื้องจะไม่ทำงานถ้าไม่ได้ตามหลังพยัญชนะต้นทันที เช่น เป็นตัวสะกดของสระอา หรือมีสระอื่นมาคั่นกลาง กล่าวคือ &lt;q&gt;&lt;code&gt;blwf&lt;/code&gt;&lt;/q&gt; ดูจะถูกเรียกเฉพาะในตำแหน่งพยัญชนะซ้อนกันเท่านั้น ไม่เรียกในตำแหน่งตัวสะกด และอีกข้อหนึ่งคือกฎ ligature สำหรับ &lt;q&gt;นา&lt;/q&gt; ไม่ทำงานเมื่อมีอักขระซ้อนบน/ล่าง&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/enc-word-use.png&quot; /&gt;
  
&lt;/figure&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/enc-word-use-2.png&quot; /&gt;
  
&lt;/figure&gt;

&lt;h4&gt;สรุป&lt;/h4&gt;

&lt;p&gt;ประเด็นต่างๆ ที่พบ พอจะสรุปได้ตังตาราง&lt;/p&gt;

&lt;table border=&quot;1&quot;&gt;
&lt;tbody&gt;&lt;tr valign=&quot;top&quot;&gt;
  &lt;th&gt;ประเด็น&lt;/th&gt;
  &lt;th&gt;ใช้ USE&lt;/th&gt;
  &lt;th&gt;เลี่ยง USE&lt;/th&gt;
&lt;/tr&gt;
&lt;tr valign=&quot;top&quot;&gt;
  &lt;td&gt;วิธีการ&lt;/td&gt;
  &lt;td&gt;
    &lt;ul&gt;
      &lt;li&gt; &lt;code&gt;lana&lt;/code&gt; script tag &lt;/li&gt;
      &lt;li&gt; GSUB ตาม USE &lt;/li&gt;
      &lt;li&gt; ตัด dotted circle &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/td&gt;
  &lt;td&gt;
    &lt;ul&gt;
      &lt;li&gt; &lt;code&gt;DFLT&lt;/code&gt; script tag &lt;/li&gt;
      &lt;li&gt; GSUB อย่างละเอียด &lt;/li&gt;
      &lt;li&gt; อาจมี dotted circle ได้ &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/td&gt;
&lt;/tr&gt;
&lt;tr valign=&quot;top&quot;&gt;
  &lt;td&gt;การ encode ข้อความ&lt;/td&gt;
  &lt;td&gt;กึ่ง visual (ขัดสามัญสำนึกนิดหน่อย)&lt;/td&gt;
  &lt;td&gt;ตามหลักการสะกดคำ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr valign=&quot;top&quot;&gt;
  &lt;td&gt;แอปที่รองรับ&lt;/td&gt;
  &lt;td&gt;Harfbuzz app&lt;a href=&quot;http://thep.blogspot.com/feeds/posts/default?alt=rss#foot-hb&quot;&gt;&lt;sup&gt;*&lt;/sup&gt;&lt;/a&gt;, MS Word (บางส่วน)&lt;/td&gt;
  &lt;td&gt;Harfbuzz app&lt;a href=&quot;http://thep.blogspot.com/feeds/posts/default?alt=rss#foot-hb&quot;&gt;&lt;sup&gt;*&lt;/sup&gt;&lt;/a&gt;, Notepad&lt;/td&gt;
&lt;/tr&gt;
&lt;tr valign=&quot;top&quot;&gt;
  &lt;td&gt;อาการเมื่อไม่รองรับ&lt;/td&gt;
  &lt;td&gt;
    &lt;ul&gt;
      &lt;li&gt; MS Word
           &lt;ul&gt;
             &lt;li&gt; กฎ &lt;code&gt;blwf&lt;/code&gt; ในตำแหน่งตัวสะกดไม่ทำงาน &lt;/li&gt;
             &lt;li&gt; กฎ ligature &lt;q&gt;นา&lt;/q&gt; ไม่ทำงานถ้ามีอักขระบน/ล่างแทรก &lt;/li&gt;
           &lt;/ul&gt;
           &lt;/li&gt;
      &lt;li&gt; Notepad และแอปที่รองรับ OpenType แบบผิวเผิน
           &lt;ul&gt;
             &lt;li&gt; ไม่มีกฎไหนทำงานเลย &lt;/li&gt;
           &lt;/ul&gt;
           &lt;/li&gt;
      &lt;li&gt; ทุกแอป
           &lt;ul&gt;
             &lt;li&gt; ไม้กั๋งไหลไม่ไหล &lt;/li&gt;
           &lt;/ul&gt;
           &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/td&gt;
  &lt;td&gt;
    &lt;ul&gt;
      &lt;li&gt; MS Word
           &lt;ul&gt;
             &lt;li&gt; &lt;code&gt;ccmp&lt;/code&gt;: การ reorder สระหน้า, ระวง ไม่ทำงาน &lt;/li&gt;
             &lt;li&gt; &lt;code&gt;liga&lt;/code&gt;: reorder สระหน้าซ้ำสองตำแหน่ง &lt;/li&gt;
           &lt;/ul&gt;
           &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;&lt;a name=&quot;foot-hb&quot;&gt;&lt;sup&gt;*&lt;/sup&gt;&lt;/a&gt;Harfbuzz app เช่น LibreOffice, Firefox, Gedit, Mousepad ฯลฯ&lt;/p&gt;

&lt;p&gt;จึงพอสรุปได้ว่ายังมีความแตกต่างระหว่างข้อกำหนดในร่างฯ กับสิ่งที่ USE รองรับจริง ทำให้ไม่ว่าจะพยายามอย่างไรก็จะมีข้อบกพร่องเกิดขึ้นเสมอ และแอปที่มีปัญหาเสมอๆ ก็คือ MS Word&lt;/p&gt;

&lt;p&gt;หากเลือกใช้ข้อกำหนด USE ทุกแอปที่รองรับ USE ก็จะได้การรองรับแบบ &lt;q&gt;เกือบๆ&lt;/q&gt; ครบถ้วน (โดย MS Word จะมีปัญหามากกว่าเพื่อนสักหน่อย) โดยแลกกับลำดับการ encode ที่ผิดธรรมชาติของผู้ใช้ ซึ่งเป็นการแลกที่ผมคิดว่าไม่คุ้ม เพราะจะมีผลให้เกิดเอกสารที่ encode แปลกๆ เกิดขึ้นในระหว่างที่ USE ยังไม่พร้อม แถมสิ่งที่ได้คืนมาก็ยังไม่ใช่สิ่งที่สมบูรณ์เสียด้วย&lt;/p&gt;

&lt;p&gt;ในขณะที่หากเลือกหลีกเลี่ยง USE แอปส่วนใหญ่ยกเว้น MS Word ก็จะสามารถจัดแสดงอักษรธรรมได้สมบูรณ์ (ดังกล่าวไว้ใน &lt;a href=&quot;https://thep.blogspot.com/2025/04/lao-tham-font-vs-use.html&quot;&gt;blog ที่แล้ว&lt;/a&gt;) โดยที่ผู้ใช้ก็ยังคงใช้ encoding แบบเก่าได้เช่นเดิม และเมื่อไรที่ USE พร้อม ก็เพียงแปลง encoding ไปเป็นแบบใหม่ (ซึ่งอาจจะอัตโนมัติหรือ manual ก็ค่อยว่ากัน) โดยไม่ต้องมี encoding ชั่วคราวของ USE มาแทรกกลางเป็นชนิดที่สามให้เกิดความสับสนเพิ่ม โดยแลกกับการทิ้ง MS Word ที่ยังไงก็ไม่สมบูรณ์อยู่แล้ว และแนะนำให้ผู้ใช้อักษรธรรมใช้ LibreOffice หรือ Notepad (ซึ่งเป็นผลพลอยได้) ในการเตรียมเอกสารแทน ส่วนเว็บเบราว์เซอร์นั้นไม่เป็นปัญหา เพราะเบราว์เซอร์ส่วนใหญ่ก็ใช้ Harfbuzz เป็นฐานกันอยู่แล้ว การรองรับก็จะเหมือนๆ กับใน LibreOffice นั่นแล&lt;/p&gt;

&lt;p&gt;ด้วยเหตุนี้ ผมจึงเลือกที่จะสร้างฟอนต์อักษรธรรมที่ &lt;strong&gt;หลีกเลี่ยง USE&lt;/strong&gt; ต่อไป จนกว่า USE จะพร้อมจริงๆ&lt;/p&gt;</description>
	<pubDate>Sun, 06 Apr 2025 10:04:00 +0000</pubDate>
	<author>noreply@blogger.com (Thep)</author>
</item>
<item>
	<title>Thep: Lao Tham Font vs USE</title>
	<guid>tag:blogger.com,1999:blog-6815053.post-6509028723707958723</guid>
	<link>http://thep.blogspot.com/2025/04/lao-tham-font-vs-use.html</link>
	<description>&lt;p&gt;บันทึกการกลับมาทำฟอนต์อักษรธรรมอีกครั้ง หลังจาก commit ล่าสุด 4 ปีที่แล้ว โดยในช่วงหลังของการทำงานรอบนั้น มีความเปลี่ยนแปลงสำคัญใน Harfbuzz ก่อนที่ผมจะวางมือไปทำอย่างอื่น คือ &lt;a href=&quot;https://www.phoronix.com/news/HarfBuzz-1.0-Released&quot;&gt;มีการใช้ Universal Shaping Engine (USE) ตามข้อกำหนดของไมโครซอฟท์&lt;/a&gt; ทำให้กฎบางข้อหยุดทำงาน เช่น การจัดการไม้กั๋งไหล (ลาวเรียก &lt;q&gt;ไม้อังแล่น&lt;/q&gt;) แต่ผมก็ไม่ได้ไปติดตาม&lt;/p&gt;

&lt;p&gt;ในเอกสาร &lt;a href=&quot;https://learn.microsoft.com/en-us/typography/script-development/use&quot;&gt;Creating and supporting OpenType fonts for the Universal Shaping Engine&lt;/a&gt; ของไมโครซอฟท์ ได้อธิบายขั้นตอนต่างๆ ที่ USE จะเรียกใช้กฎในฟอนต์ โดยที่ USE เองก็มีการประมวลผลภายในเองบางส่วนด้วย ตามแต่อักษรที่รองรับ โดยสำหรับอักษรธรรมก็มีเชิงอรรถให้ปวดใจว่า&lt;/p&gt;

&lt;blockquote&gt;
&lt;strong&gt;Note:&lt;/strong&gt; Tai Tham support is currently limited. Additional encoding work is required for full text representation to be possible.
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;&lt;q&gt;การรองรับอักษรธรรมยังคงจำกัดอยู่ในตอนนี้ ยังต้องทำงานด้านการกำหนดรหัสกันต่อไปเพื่อจะให้ได้รหัสที่สามารถแทนข้อความได้เต็มที่&lt;/q&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ซึ่งเมื่อไปตรวจสอบเอกสารที่เกี่ยวข้อง ก็พบเอกสาร &lt;a href=&quot;https://www.unicode.org/L2/L2019/19365-tai-tham-structure.pdf&quot;&gt;Structuring Tai Tham Unicode&lt;/a&gt; (L2/19-365) โดย Martin Hosken ซึ่งเป็นร่างข้อเสนอที่จะปรับลำดับการลงรหัสอักขระอักษรธรรมจาก &lt;a href=&quot;https://www.unicode.org/L2/L2005/05095r-lanna.pdf&quot;&gt;แบบเริ่มแรก&lt;/a&gt; (L2/05-095R) เพื่อการวาดแสดงด้วย USE ซึ่งลำดับแบบใหม่ค่อนข้างแตกต่างจากลำดับการสะกดในใจพอสมควร และข้อเสนอใหม่ก็ยังคงเป็นฉบับร่าง จึงเกิดความไม่แน่นอนว่าแนวทางการลงรหัสปัจจุบันจะเป็นแบบไหน&lt;/p&gt;

&lt;p&gt;เนื่องจาก&lt;a href=&quot;https://www.facebook.com/Chyasiri&quot;&gt;พระอาจารย์ชยสิริ ชยสาโร&lt;/a&gt; ประสงค์จะให้ผมเพิ่มอักษรธรรมลงในฟอนต์ Laobuhan ของท่าน ผมจึงถือโอกาสทดลองทำตามข้อกำหนดของ USE อันใหม่เสียเลย โดยพยายามทดสอบบน Windows 11 ด้วย นอกเหนือจากที่เคยทดสอบเฉพาะบนลินุกซ์ โดยในข้อกำหนดใหม่ USE มีการ reorder สระหน้าให้ จึงไม่ต้องทำในฟอนต์เองอีกต่อไป สิ่งที่ควรทำ (เรียงตามลำดับการเรียกใช้โดย USE) จึงเป็น:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt; &lt;code&gt;pref&lt;/code&gt; (Pre-base forms) เพื่อระบุตำแหน่งของระวง เพื่อที่ USE จะ reorder ไปไว้หน้าพยัญชนะต้นให้ในภายหลัง &lt;/li&gt;
  &lt;li&gt; &lt;code&gt;rphf&lt;/code&gt; (Reph forms) ความจริงเป็นกฎสำหรับ reorder &lt;q&gt;เรผะ&lt;/q&gt; ของอักษรอินเดีย ที่ดูแล้วน่าจะใช้กับ &lt;q&gt;ไม้กั๋งไหล&lt;/q&gt; ของอักษรธรรมได้ แต่เมื่อทดลองทำจริงแล้วไม่เป็นผล ซึ่งในเอกสารของไมโครซอฟท์เองก็ระบุไว้ว่า:
       &lt;blockquote&gt;
         Note that the category REPHA is not currently supported by USE.
       &lt;/blockquote&gt;
ซึ่งหมายความว่า &lt;code&gt;rphf&lt;/code&gt; เองก็จะยังไม่ทำงาน &lt;/li&gt;
  &lt;li&gt; &lt;code&gt;blwf&lt;/code&gt; (Below-base forms) เพื่อทำตัวห้อย ตัวเฟื้อง &lt;/li&gt;
  &lt;li&gt; &lt;code&gt;liga&lt;/code&gt; (Standard ligatures) เพื่อทำรูปเขียนพิเศษ เช่น &lt;q&gt;นา&lt;/q&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ผลการทดสอบคือ แอปที่ใช้ Harfbuzz (GTK, LibreOffice, Firefox) และ MS Word วาดแสดงอักษรธรรมได้ดี ยกเว้นในบางกรณี เช่น สระอาที่ตามหลังวรรณยุกต์จะมี dotted circle แทรกเข้ามา และตัว ล ห้อย (ที่ไม่ใช้ SAKOT) ที่ใช้ร่วมกับสระหน้าจะแสดงถูกต้องเฉพาะเมื่อลงรหัสด้วยลำดับที่เหมาะสมเท่านั้น กล่าวคือ ถ้าใช้ structure ข้อความแบบใหม่ที่ออกแบบให้รองรับ USE ก็ &lt;em&gt;น่าจะ&lt;/em&gt; แสดงได้ถูกต้องเป็นส่วนมาก&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/LBT-Writer-USE.png&quot; width=&quot;75%&quot; /&gt;
  อักษรธรรมบน LibreOffice Writer แบบใช้ USE
&lt;/figure&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/LBT-Word-USE.png&quot; width=&quot;75%&quot; /&gt;
  อักษรธรรมบน MS Word แบบใช้ USE
&lt;/figure&gt;

&lt;p&gt;แต่กับ Notepad บน Windows ดูเหมือนกฎต่างๆ จะไม่ทำงานเลย! สถานการณ์อาจต่างจากลินุกซ์ที่แอปแทบทุกตัวใช้ Harfbuzz กันหมด แต่บน Windows ยังแยก implement กันอยู่&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/LBT-Note-USE.png&quot; width=&quot;80%&quot; /&gt;
  อักษรธรรมบน Windows Notepad แบบใช้ USE
&lt;/figure&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/LBT-Mousepad-USE.png&quot; width=&quot;600&quot; /&gt;
  อักษรธรรมบน Linux Mousepad แบบใช้ USE
&lt;/figure&gt;

&lt;p&gt;แต่ปัญหา dotted circle ในบางกรณีของ USE ก็ยังทำให้ผมต้องค้นหาข้อมูลต่อ ทั้งไล่ซอร์สโค้ดของ Harfbuzz ทั้งค้นเว็บ จนไปเจอ &lt;a href=&quot;https://typedrawers.com/discussion/4499/opting-out-of-the-universal-shaping-engine&quot;&gt;โพสต์ของ Richard Wordingham&lt;/a&gt; เล่าปัญหาเดียวกันที่เขาเจอ โดยได้พูดถึงวิธีหลบเลี่ยง USE ด้วย โดยในทุกกฎ GSUB, GPOS ไม่ต้องระบุรหัสอักษรเป็น &lt;q&gt;&lt;code&gt;lana&lt;/code&gt;&lt;/q&gt; เลย เพียงใช้รหัสอักษร &lt;q&gt;&lt;code&gt;DFLT&lt;/code&gt;&lt;/q&gt; ก็พอ ซึ่งถ้าเป็น Harfbuzz ก็จะไปเรียก default engine แทน USE ซึ่งฟอนต์ก็ต้องเตรียมกฎ GSUB ให้มันทำงานทุกอย่างแทน USE ทั้งหมด ผ่าน OpenType feature เท่าที่ใช้รองรับ &lt;a href=&quot;https://learn.microsoft.com/en-us/typography/script-development/standard&quot;&gt;Standard Scripts&lt;/a&gt; ซึ่งก็จะมี feature จำนวนจำกัดให้ใช้ เช่น &lt;q&gt;&lt;code&gt;ccmp&lt;/code&gt;&lt;/q&gt; และ &lt;q&gt;&lt;code&gt;liga&lt;/code&gt;&lt;/q&gt; เป็นต้น&lt;/p&gt;

&lt;p&gt;เรื่องกฎไม่ใช่เรื่องยาก เพราะฟอนต์ Khottabun ที่ผมสร้างตั้งแต่ก่อนที่ Harfbuzz จะใช้ USE ก็ทำทุกอย่างเองหมดอยู่แล้ว ก็เลยหยิบมาทดลองได้ทันที โดยตัดรหัสอักษร &lt;q&gt;&lt;code&gt;lana&lt;/code&gt;&lt;/q&gt; ออกจากกฎ &lt;q&gt;&lt;code&gt;ccmp&lt;/code&gt;&lt;/q&gt; ที่ใช้ทั้งหมด&lt;/p&gt;

&lt;p&gt;ผลปรากฏว่า มันยังคงวาดแสดงได้อย่างสมบูรณ์บน Harfbuzz แต่คราวนี้มันทำงานบน Notepad บน Windows ด้วย! โดยในทั้งสองกรณี กฎที่เขียนไว้สำหรับไม้กั๋งไหลที่เคยไม่ทำงานบน Harfbuzz ก็กลับทำงานเรียบร้อย! (ดูตัวอย่างคำว่า มงฺคล แบบแรก)&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/Khot-Writer-NoLana.png&quot; width=&quot;75%&quot; /&gt;
  อักษรธรรมบน LibreOffice Writer แบบใช้รหัสอักษร &lt;q&gt;&lt;code&gt;DFLT&lt;/code&gt;&lt;/q&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/Khot-Note-NoLana.png&quot; width=&quot;80%&quot; /&gt;
  อักษรธรรมบน Windows Notepad แบบใช้รหัสอักษร &lt;q&gt;&lt;code&gt;DFLT&lt;/code&gt;&lt;/q&gt;
&lt;/figure&gt;

&lt;p&gt;แต่ข่าวร้ายคือ มันเละบน MS Word&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;https://linux.thai.net/~thep/shots/tham-font/Khot-Word-NoLana.png&quot; width=&quot;75%&quot; /&gt;
  อักษรธรรมบน MS Word แบบใช้รหัสอักษร &lt;q&gt;&lt;code&gt;DFLT&lt;/code&gt;&lt;/q&gt;
&lt;/figure&gt;

&lt;p&gt;ซึ่งจากการทดลองก็สรุปได้ว่ามันเกิดจาก:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt; ข้อจำกัดของ &lt;q&gt;&lt;code&gt;ccmp&lt;/code&gt;&lt;/q&gt; บน engine ของ MS Word ที่ดูจะไม่รองรับ contextual substitution ที่ซับซ้อน (เข้าใจว่าทำได้แค่ multiple substitution และ ligature substitution อย่างง่ายเท่านั้น) &lt;/li&gt;
  &lt;li&gt; engine ของ MS Word ยังคงใช้ USE เช่นเดิม ทำให้ถึงแม้จะเปลี่ยนไปใช้ &lt;q&gt;&lt;code&gt;liga&lt;/code&gt;&lt;/q&gt; ที่สามารถทำ contextual substitution ซับซ้อนได้ ก็จะเกิดการ reorder สระหน้าซ้ำซ้อนกันระหว่างโดยตัว engine เองก้บโดยกฎในฟอนต์จนสระหน้าสามารถเลื่อนข้ามพยัญชนะไปได้ถึง 2 ตำแหน่ง &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ถ้าคิดตามหลักเหตุผลแล้ว ถ้า &lt;q&gt;&lt;code&gt;ccmp&lt;/code&gt;&lt;/q&gt; ที่ USE เรียกใช้ในขั้น preprocessing สามารถทำงานได้อย่างถูกต้อง โดยให้กฎแทรก glyph ผีสักตัว (เช่น ZWNJ) ไว้หน้าสระหน้าที่สลับลำดับแล้ว เพื่อให้มันคั่นระหว่างสระหน้ากับพยัญชนะที่อยู่ก่อนหน้าไว้ ก็ควรจะสามารถป้องกัน USE ไม่ให้ reorder ซ้ำอีกได้ แต่ในเมื่อ DirectWrite engine ที่ MS Word ใช้ไม่รองรับ &lt;q&gt;&lt;code&gt;ccmp&lt;/code&gt;&lt;/q&gt; ที่ซับซ้อน (แบบที่ Harfbuzz ทำ) มันก็จบเห่ตั้งแต่ต้น ส่วน &lt;q&gt;&lt;code&gt;liga&lt;/code&gt;&lt;/q&gt; หรือ &lt;q&gt;&lt;code&gt;clig&lt;/code&gt;&lt;/q&gt; ที่รองรับ contextual substitution แบบซับซ้อนได้ ก็ถูกเรียกทำงานหลังการ reorder ภายในของ USE ไปแล้ว จึงไม่สามารถควบคุมอะไรได้ทันการณ์&lt;/p&gt;

&lt;p&gt;ในเมื่อ USE ก็ไม่สมบูรณ์ จะเลี่ยง USE ก็ติดปัญหากับ MS Word ผมจึงอยู่บนทางเลือก:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt; ใช้ USE ไปเลย แล้วรอให้มีการแก้ปัญหาของ USE อีกที &lt;/li&gt;
  &lt;li&gt; เลี่ยง USE ต่อไป โดยได้การทำงานของไม้กั๋งไหลเพิ่มมาด้วย แต่ยอมทิ้งการรองรับบน MS Word &lt;/li&gt;
  &lt;li&gt; เลี่ยง USE แบบต้องปรับฟอนต์ขนานใหญ่ให้ใช้ &lt;q&gt;&lt;code&gt;ccmp&lt;/code&gt;&lt;/q&gt; ในการ reorder ให้ได้ ผ่าน ligature glyph แล้วค่อยรื้อกลับใหม่อีกทีเมื่อ USE พร้อม &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;การเลือกครั้งนี้จะไม่ยากเลยถ้าการรองรับอักษรธรรมใน Unicode มีทิศทางที่ชัดเจน แต่ปัญหาคือมันไม่ขยับมา 6 ปีแล้ว&lt;/p&gt;

&lt;p&gt;แอปที่ใช้ Harfbuzz นั้นทำงานได้กับทุกทางเลือก ปัญหาอยู่ที่แอปนอกเหนือจากนั้น โดยในที่นี้คือ MS Word กับ Notepad ซึ่งเราต้องเลือกเอาอย่างใดอย่างหนึ่ง ถ้าใช้ USE ก็จะได้ MS Word ที่ทำงานได้เท่าที่ USE รองรับ ถ้าไม่ใช้ USE ก็จะได้ Notepad ที่ทำงานเต็มรูปแบบ&lt;/p&gt;

&lt;p&gt;โดย Notepad เองก็ถือเป็นตัวแทนของแอปอื่นๆ ที่รองรับ OpenType แบบผิวเผินด้วย ในขณะที่ MS Word ก็น่าจะเป็นแอปหลักแอปหนึ่งที่ผู้ใช้ฟอนต์จะใช้เตรียมเอกสาร (แต่จะให้ดี LibreOffice เป็นทางเลือกที่เปิดกว้างต่อ solution ต่างๆ มากกว่า)&lt;/p&gt;

&lt;p&gt;ผมจะวิเคราะห์ใน blog หน้าว่าจะพิจารณาชั่งน้ำหนักอย่างไรต่อไป&lt;/p&gt;&lt;/figure&gt;</description>
	<pubDate>Tue, 01 Apr 2025 05:06:00 +0000</pubDate>
	<author>noreply@blogger.com (Thep)</author>
</item>
<item>
	<title>Vee: I have been told to avoid linked lists.</title>
	<guid>https://dev.to/veer66/i-have-been-told-to-avoid-linked-lists-24ja</guid>
	<link>https://dev.to/veer66/i-have-been-told-to-avoid-linked-lists-24ja</link>
	<description>&lt;p&gt;I've been told to avoid linked lists because their elements are scattered everywhere, which can be true in some cases. However, I wonder what happens in loops, which I use frequently. I tried to inspect memory addresses of list elements of these two programs run on SBCL.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight common_lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;CL-USER&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;setq&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;*a-list*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;CL-USER&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sb-kernel:get-lisp-obj-address&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;*a-list*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;69517814583&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;37&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bits,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#x102F95AB37&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;CL-USER&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sb-kernel:get-lisp-obj-address&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cdr&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;*a-list*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;69517814567&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;37&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bits,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#x102F95AB27&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;CL-USER&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sb-kernel:get-lisp-obj-address&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cddr&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;*a-list*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;69517814551&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;37&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bits,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#x102F95AB17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;CL-USER&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sb-kernel:get-lisp-obj-address&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cddr&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;*a-list*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;69517814551&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;37&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bits,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#x102F95AB17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight common_lisp&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;CL-USER&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;setq&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;*a-list*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
              &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;CL-USER&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sb-kernel:get-lisp-obj-address&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;*a-list*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;69518319943&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;37&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bits,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#x102F9D6147&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;CL-USER&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sb-kernel:get-lisp-obj-address&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cdr&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;*a-list*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;69518319927&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;37&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bits,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#x102F9D6137&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;CL-USER&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sb-kernel:get-lisp-obj-address&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cddr&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;*a-list*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;69518319911&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;37&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bits,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#x102F9D6127&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both programs, the list elements are not scattered. So, if scattered list elements were an issue for these simple cases, you probably used the wrong compiler or memory allocator.&lt;/p&gt;</description>
	<pubDate>Sun, 23 Mar 2025 08:18:12 +0000</pubDate>
</item>
<item>
	<title>Kitt: GIMP 3.0 Released</title>
	<guid>https://kitty.in.th/?p=20732</guid>
	<link>https://kitty.in.th/index.php/2025/03/18/gimp-3-0-released/</link>
	<description>The wait is over. Here we go .. https://www.gimp.org/news/2025/03/16/gimp-3-0-released/ We may need to update the scripts, though.</description>
	<pubDate>Tue, 18 Mar 2025 01:56:13 +0000</pubDate>
</item>
<item>
	<title>Kitt: LLM Safety</title>
	<guid>https://kitty.in.th/?p=20676</guid>
	<link>https://kitty.in.th/index.php/2025/02/01/llm-safety/</link>
	<description>เรื่องสมมติที่เกิดขึ้นจริง ในฝั่ง cybersecurity เราเริ่มใช้ AI ในการป้องกันมาพักนึงแล้ว และพบการโจมตีมากขึ้นเรื่อย ๆ รวมถึงเห็นภัยคุกคามใหม่ ๆ ที่เชื่อมโยงกับ AI ด้วยเหมือนกันในทางบวก ฝั่งป้องกัน เราใช้ AI ช่วยในการ summarize logs เชื่อมโยง security events เพื่อ discovery การโจมตี discover สิ่งที่ rule-based ทำไม่ได้ หรือ overload มนุษย์มาก ๆ ในทางลบ เราเห็น web crawlers / spiders ฝั่ง AI วิ่งเก็บข้อมูลหน้าเว็บหนักกว่าเดิม 5 – 10 เท่าจากปกติ ซึ่งมันกิน resources เด้อจ้า .. ทั้ง CPU, mem, egress ที่ต้องประมวลผลตอบสนอบขึ้นหมดเลย … &lt;a class=&quot;more-link&quot; href=&quot;https://kitty.in.th/index.php/2025/02/01/llm-safety/&quot;&gt;Continue reading &lt;span class=&quot;screen-reader-text&quot;&gt;LLM Safety&lt;/span&gt; &lt;span class=&quot;meta-nav&quot;&gt;→&lt;/span&gt;&lt;/a&gt;</description>
	<pubDate>Sat, 01 Feb 2025 08:48:23 +0000</pubDate>
</item>
<item>
	<title>Kitt: DeepSeek-R1</title>
	<guid>https://kitty.in.th/?p=20725</guid>
	<link>https://kitty.in.th/index.php/2025/01/29/deepseek-r1/</link>
	<description>ลองเอา deepseek-r1:1.5b ตัวเล็กสุด มารันใน notebook ตัวเอง มันเก่งจริงอย่างที่หลายคนอวยยศแฮะ response เร็ว กิน resource น้อย (อจก. ตามไปอ่าน architecture ของ deepseek แล้ว ในทางวิศวกรรม #ของแทร่ อยู่เด้อ) ประเด็นคือออ .. model ขนาด 1-2b parameters หลาย ๆ models นี่ คอมพิวเตอร์ทั่ว ๆ ไป มี memory เหลือสัก 1.5-2 GB ก็รันได้แล้วนะครับ ไม่ต้องมี GPU/NPU ช่วย accelerate ก็รันได้ (เครื่อง อจก. ก็ไม่มี GPU/NPU) ยิ่งถ้ามี AI-accelerated (e.g., CPU+NPU, Copilot+ PC) ที่กำลังทยอยออกมาวางขายผู้ใช้งานทั่วไป การรัน … &lt;a class=&quot;more-link&quot; href=&quot;https://kitty.in.th/index.php/2025/01/29/deepseek-r1/&quot;&gt;Continue reading &lt;span class=&quot;screen-reader-text&quot;&gt;DeepSeek-R1&lt;/span&gt; &lt;span class=&quot;meta-nav&quot;&gt;→&lt;/span&gt;&lt;/a&gt;</description>
	<pubDate>Wed, 29 Jan 2025 01:39:30 +0000</pubDate>
</item>
<item>
	<title>Kitt: 2025/1 Information on UTC – TAI</title>
	<guid>https://kitty.in.th/?p=20721</guid>
	<link>https://kitty.in.th/index.php/2025/01/08/2025-1-leap-second-announcement/</link>
	<description>“NO leap second will be introduced at the end of June 2025. The difference between Coordinated Universal Time UTC and the International Atomic Time TAI is : from 2017 January 1, 0h UTC, until further notice : UTC-TAI = -37 s” — IERS EOP Bulletin C#69</description>
	<pubDate>Sun, 26 Jan 2025 14:12:08 +0000</pubDate>
</item>
<item>
	<title>Kitt: AWS Thailand Region</title>
	<guid>https://kitty.in.th/?p=20718</guid>
	<link>https://kitty.in.th/index.php/2025/01/08/aws-thailand-region/</link>
	<description>มาแล้วก็ใช้สิครับ AWS Asia Pacific (Thailand) Region .. \(^^)/ ref. https://aws.amazon.com/local/thailand/</description>
	<pubDate>Sun, 26 Jan 2025 14:07:18 +0000</pubDate>
</item>
<item>
	<title>Kitt: CVE: rsync</title>
	<guid>https://kitty.in.th/?p=20716</guid>
	<link>https://kitty.in.th/index.php/2025/01/15/cve-rsync/</link>
	<description>หัวทีม debian mirror แจ้งข่าวเข้า mailling list แต่เช้าว่า “สูเจ้าจงอัปเกรด rsync ASAP” ต้นเรื่องคือ 3.3 &amp;gt;= rsync &amp;gt;= 3.2.7 มี heap overflow และอื่น ๆ lot นี้ พบ และ fix ไปแล้ว ~ 6 CVEs ครับ main distros release fixes แล้วเมื่อไม่กี่ชั่วโมงที่ผ่านมา</description>
	<pubDate>Sun, 26 Jan 2025 14:05:43 +0000</pubDate>
</item>
<item>
	<title>Kitt: หมูแฮม</title>
	<guid>https://kitty.in.th/?p=20713</guid>
	<link>https://kitty.in.th/index.php/2025/01/16/%e0%b8%ab%e0%b8%a1%e0%b8%b9%e0%b9%81%e0%b8%ae%e0%b8%a1/</link>
	<description>ออกจากดาวหมา มาอยู่บ้านนี้สิบหกปี..วันนี้ลุงหมูแฮมได้กลับดาวละน้าาาาา</description>
	<pubDate>Sun, 26 Jan 2025 14:03:27 +0000</pubDate>
</item>
<item>
	<title>Kitt: คืนชีพ skuld.kitty.in.th</title>
	<guid>https://kitty.in.th/?p=20671</guid>
	<link>https://kitty.in.th/index.php/2025/01/01/%e0%b8%84%e0%b8%b7%e0%b8%99%e0%b8%8a%e0%b8%b5%e0%b8%9e-skuld-kitty-in-th/</link>
	<description>10:00 31 ธ.ค. 2024 หลังจากที่ได้ instant ใหม่ OS เดิม (Ubuntu 16.04) เป็นเครื่องเปล่า ๆ ที่ไม่มีข้อมูล สิ่งแรกที่พยายามทำคือกู้จาก snapshot เดียวที่มีอยู่ ทำให้ได้ kitty.in.th ที่มีข้อมูลถึงประมาณต้นเดือนมีนาคม 2017 manually install All-in-One WP migration ทำ site backup ได้ไฟล์ขนาด 2 GB ซึ่งใหญ่เกิน จะ recovery ได้ฟรี แต่ก็ยังดีกว่าไม่มีอะไรเลย หลังจาก มี backup .wpress แล้ว dump mysql, tar gz web root เก็บ ย้ายมาเก็บที่ notebook อีกหนึ่งสำเนา พร้อมล้างเครื่องแล้ว .. กด … &lt;a class=&quot;more-link&quot; href=&quot;https://kitty.in.th/index.php/2025/01/01/%e0%b8%84%e0%b8%b7%e0%b8%99%e0%b8%8a%e0%b8%b5%e0%b8%9e-skuld-kitty-in-th/&quot;&gt;Continue reading &lt;span class=&quot;screen-reader-text&quot;&gt;คืนชีพ skuld.kitty.in.th&lt;/span&gt; &lt;span class=&quot;meta-nav&quot;&gt;→&lt;/span&gt;&lt;/a&gt;</description>
	<pubDate>Sun, 26 Jan 2025 14:00:23 +0000</pubDate>
</item>
<item>
	<title>Kitt: 2024 Password Guidelines</title>
	<guid>https://kitty.in.th/?p=20692</guid>
	<link>https://kitty.in.th/index.php/2025/01/22/2024-password-guidelines/</link>
	<description>รหัสผ่านไม่จำเป็นต้องมีสัญลักษณ์ผสมก็ได้ มันทำให้จำยาก พิมพ์ผิดง่าย และไม่ได้ช่วยให้ปลอดภัยอย่างที่เคยคิด แต่จะต้องตั้งรหัสผ่านให้ยาว ๆ (ต่ำสุด ๆ คือ 12 ตัวอักษร แนะนำว่า 15 ขึ้นไป) รหัสผ่านตั้งยาว ๆ ได้ ก็จะใช้ยาว ๆ ได้เลย ไม่จำเป็นต้องเปลี่ยนทุก 90 วันเหมือนที่เคยแนะนำกันอีกแล้ว จะใช้นานเท่าไหร่ก็ไม่ว่า จะบังคับเปลี่ยนก็ต่อเมื่อมีหลักฐานเพียงพอว่ารหัสผ่านรั่วไหล อย่าใช้รหัสผ่านเดียวกันหลายเว็บ/แอป มันมีความเสี่ยงที่เว็บ/แอป ทำรหัสผ่านเรารั่วไหล แล้วเอารหัสผ่านนั้นไป login เว็บอื่น ๆ ต่อ สำหรับคนที่กลัวจำรหัสผ่านยาว ๆ ไม่ได้ เรามีเทคโนโลยี password manager ช่วยตั้งและจำรหัสผ่านแทนได้นะครับ จะใช้ Google Chrome, Apple Password ไปเลยก็ได้ หรือจะใช้ LastPass, Dashlane, Bitwarden, 1Password ก็ได้ เดี๋ยวนี้ รหัสผ่านอย่างเดียวไม่พอจริง ๆ … &lt;a class=&quot;more-link&quot; href=&quot;https://kitty.in.th/index.php/2025/01/22/2024-password-guidelines/&quot;&gt;Continue reading &lt;span class=&quot;screen-reader-text&quot;&gt;2024 Password Guidelines&lt;/span&gt; &lt;span class=&quot;meta-nav&quot;&gt;→&lt;/span&gt;&lt;/a&gt;</description>
	<pubDate>Sun, 26 Jan 2025 13:59:44 +0000</pubDate>
</item>
<item>
	<title>Kitt: Talk is cheap. Show me the code.</title>
	<guid>https://kitty.in.th/?p=20709</guid>
	<link>https://kitty.in.th/index.php/2025/01/17/talk-is-cheap-show-me-the-code/</link>
	<pubDate>Sun, 26 Jan 2025 13:56:44 +0000</pubDate>
</item>
<item>
	<title>Vee: JSON Manipulation</title>
	<guid>https://dev.to/veer66/json-manipulation-1183</guid>
	<link>https://dev.to/veer66/json-manipulation-1183</link>
	<description>&lt;p&gt;There are many ways to manipulate JSON. I reviewed a few rapid ways today, which are using a command line tool called &lt;code&gt;jq&lt;/code&gt; and libraries that support JSONPath query language.&lt;/p&gt;

&lt;h1&gt;
  
  
  jq
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;Awk&lt;/code&gt; is a powerful domain-specific language for text processing, but it lacks built-in support for manipulating hierarchical data structures like trees. &lt;code&gt;jq&lt;/code&gt; fills this gap by providing a tool for transforming JSON data. However, one potential drawback is that &lt;code&gt;jq&lt;/code&gt; requires a separate installation, which may add complexity to my workflow.&lt;/p&gt;

&lt;p&gt;So I write a shell script using &lt;code&gt;jq&lt;/code&gt; to extract user's names and user's urls from a cURL response, and then output it in TSV format.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://mstdn.in.th/api/v1/timelines/public?limit=10'&lt;/span&gt; | jq &lt;span class=&quot;s1&quot;&gt;'.[].account | [.username, .url] | @tsv'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result looks like this:&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;kuketzblog      https://social.tchncs.de/@kuketzblog
cats    https://social.goose.rodeo/@cats
AlJazeera       https://flipboard.com/@AlJazeera
TheHindu        https://flipboard.com/@TheHindu
GossiTheDog     https://cyberplace.social/@GossiTheDog
kuketzblog      https://social.tchncs.de/@kuketzblog
weeklyOSM       https://en.osm.town/@weeklyOSM
juanbellas      https://masto.es/@juanbellas
noborusudou     https://misskey.io/@noborusudou
jerryd  https://mastodon.social/@jerryd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a TSV file, we can use Awk, sed, etc. to manipulate them as usual.&lt;/p&gt;

&lt;h1&gt;
  
  
  JSONPath
&lt;/h1&gt;

&lt;p&gt;JSONPath, which was explained in &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9535&quot; rel=&quot;noopener noreferrer&quot;&gt;RFC 9535&lt;/a&gt;, is supported by many libraries and applications, e.g. PostgreSQL. Still, I try to it in Python by the &lt;code&gt;jsonpath_nq&lt;/code&gt; library.&lt;br /&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight python&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jsonpath_ng&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;https://mstdn.in.th/api/v1/timelines/public?limit=10&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;compiled_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$[*].account&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matched_node&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compiled_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()):&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;matched_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matched_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It gave the same result to the shell script above. The code is a bit longer than the shell script. However, it can be integrated with many Python libraries.&lt;/p&gt;</description>
	<pubDate>Sun, 19 Jan 2025 11:55:57 +0000</pubDate>
</item>
<item>
	<title>Kitt: ป๊า</title>
	<guid>https://kitty.in.th/?p=20668</guid>
	<link>https://kitty.in.th/index.php/2024/04/18/%e0%b8%9b%e0%b9%8a%e0%b8%b2/</link>
	<description>ต้นเดือน กพ. คุณพ่อ อจก. ป่วย หมอพบลำไส้อุดตัน และภายหลังพบว่าสาเหตุมาจากมะเร็งลำไส้ใหญ่ระยะ 3 หมอ รพ.ขก. ผ่าตัดฉุกเฉินรักษาได้ทัน แต่พ่อติดเชื้อหลังผ่าตัด อจก. ย้ายพ่อมารักษาที่ รพ.ศรีฯ เชื้อดื้อยามาก ๆ ลากยาวมาจนถึงสงกรานต์ ร่างกายพ่ออ่อนแอจนมีการติดเชื้อราเพิ่ม หมอให้ยาฆ่าเชื้อ 5 ตัว ยาตัวสุดท้ายที่เหลือให้หมอใช้ได้ เป็นตัวที่แรงมาก ๆ และมีผลข้างเคียงแรงมาก ๆ แต่ก็ไม่สามารถลดการติดเชื้อได้ เราหมดทางรักษาการติดเชื้อของพ่อ พ่ออดทนกับการรับยาฆ่าเชื้อมาจนถึงเมื่อวาน เวลา 11:30 เป็นเวลาที่เราได้พบกับทีมรักษาประคับประคอง (palliative care) ครอบครัวเราตัดสินใจรับ palliative care ในช่วงท้าย ทำให้ครอบครัวเรามีเวลาอยู่กับท่าน และเลือกการประคับประคองที่ทำได้ สำหรับบางกรณี อาจจะประคองกันได้เป็นเดือน ๆ ทำให้ครอบครัวมีเวลาได้อยู่ด้วยกัน ใช้ชีวิตได้เกือบจะปกติ สำหรับกรณีของเรา ทางเลือกที่พ่อทรมานที่สุดอาจจะประคองได้ไม่กี่ชั่วโมง และทางเลือกที่ทรมานน้อยที่สุดประคองได้ไม่กี่นาที ครอบครัวเราเลือกที่พ่อทรมานน้อยที่สุด หยุดรับการให้ยาฆ่าเชื้อ จนเมื่อวานเย็น เราให้ถอด life support … &lt;a class=&quot;more-link&quot; href=&quot;https://kitty.in.th/index.php/2024/04/18/%e0%b8%9b%e0%b9%8a%e0%b8%b2/&quot;&gt;Continue reading &lt;span class=&quot;screen-reader-text&quot;&gt;ป๊า&lt;/span&gt; &lt;span class=&quot;meta-nav&quot;&gt;→&lt;/span&gt;&lt;/a&gt;</description>
	<pubDate>Wed, 01 Jan 2025 05:30:49 +0000</pubDate>
</item>

</channel>
</rss>
