CINXE.COM

gugod's blog

<?xml version="1.0" encoding="UTF-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <id>https://gugod.org/</id> <title>gugod's blog</title> <link rel="alternate" href="https://gugod.org" type="text/html"/> <entry> <id>https://gugod.org/2025/01/work-with-two-keyboard-layout-in-kde-fcitx/?52bbbc09baa0b6c409f622d35dfeea3ba961eaf2</id> <link rel="alternate" href="https://gugod.org/2025/01/work-with-two-keyboard-layout-in-kde-fcitx/" type="text/html"/> <title>如何在 KDE Plasma + Fcitx5 環境中使用兩種不同的鍵盤佈局</title> <published>2025-01-30T20:59:24+08:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>我平時使用的外接鍵盤都是在韌體層就改爲 Dvorak 佈局,但,帶筆電外出時有可能無法再帶一個鍵盤,所以希望能夠調整作業系統界面,讓我能夠在使用筆電鍵盤於外接鍵盤是都能使用 Dvorak 佈局來打字。這邊主要的需求是 </p> <ol> <li>在使用筆電鍵盤時,在軟體層將鍵盤的佈局設定爲 Dvorak。 </li> <li>在使用外接鍵盤時,在軟體層講鍵盤的佈局設定爲 QWERTY,如此一來配合外接鍵盤就是 Dvorak 佈局。 </li> <li>要有可以讓我立刻於前述兩種情景中切換的方式。 </li> </ol> <p>最後摸索出的方法是直接用 Fcitx5 內建的方式來做到。 </p> <p>修改 Fcitx5 設定。開 KDE 的「設定」App,進入「輸入法」那一區調整 Fcitx5 的設定內容。 </p> <ul> <li>準備兩個「群組」(Group)。 </li> <li>群組一爲 QWERTY。使系統佈局爲 "English (US)" </li> <li>群組二爲 Dvorak。使系統佈局爲 "English (US) - English (Dvorak)" </li> <li>在兩個群組中都加入一樣的輸入法引擎。我是先加入了 Rime 跟 Mozc。 </li> <li>進入 "Configure addons" </li> <li>在其中找到 "Wayland",點進入該區 <ul><li>將 "Allow Overriding System XKB Settings (Only support KDE5)" 這一項勾起來 </li><li>如此一來 <code>~/.config/kxkbrc</code> 便會在 fcitx5 起動時自動依照前述設定內容重新產生出來。 </li></ul></li> </ul> <p>在套用這段設定之後,以滑鼠右鍵點擊 Fcitx5 於系統工具列上的按鈕後,應可 看到切換兩群組的選單。選了其中之一個群組後,在輸入法沒有啓用的狀態下, 便會對應到該群組內的系統佈局。切換到 Rime 或 Mozc 後,也會自動對應到各 自的系統佈局。 </p> <p>最後重新開機後確認一下結果就好。 </p> </div> </content> <category term="kde"/> <category term="plasma"/> <category term="fcitx5"/> </entry> <entry> <id>https://gugod.org/2024/11/regexp-digits/?0620aef0e01d5737ce18ffb5c80830a805f10152</id> <link rel="alternate" href="https://gugod.org/2024/11/regexp-digits/" type="text/html"/> <title>能抓出「數字」的正規表示式</title> <published>2024-11-01T16:46:15+09:00</published> <author> <name>gugod</name> </author> <content type="html" xml:base="https://gugod.org">&lt;p&gt;在許多公開與非公開的程式碼中,都很常看到以 &lt;code&gt;\d&lt;/code&gt; 來判別某個輸入是否為數字。比方說像是這種試圖檢查 URI 上的 &lt;code&gt;id&lt;/code&gt; 是否只含有數字的寫法: &lt;/p&gt;&lt;pre&gt;&lt;code&gt;unless ($uri-&amp;gt;query_param('id') =~ /^\d+$/) { croak $InvalidIdException; }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這種寫法確實可以讓例如 &lt;code&gt;&amp;quot;123&amp;quot;&lt;/code&gt;、&lt;code&gt;&amp;quot;0135&amp;quot;&lt;/code&gt;、&lt;code&gt;&amp;quot;00000&amp;quot;&lt;/code&gt; 等等字串通過檢查,一定程度上算是正確的。但,其實 &lt;code&gt;\d&lt;/code&gt; 這個字元集合十分大。一般直觀可能會認爲這個集合只有十個元素,也就是跟 &lt;code&gt;[0123456789]&lt;/code&gt; 一樣。 &lt;/p&gt;&lt;p&gt;但如果對 Unicode 碼位一百萬以下逐一測試,數出所有符合 &lt;code&gt;\d&lt;/code&gt; 的字符總數。就可發現這個集合中共有 680 個元素。也就是說在 Unicode 前一百萬個符號中,有 680 個「數字」: &lt;/p&gt;&lt;pre&gt;&lt;code&gt;# perl -C7 -E 'my @digits = grep { /\d/ } map { chr($_) } 0..999999; say scalar @digits' 680&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;確實在 ASCII 當道的時代,&lt;code&gt;\d&lt;/code&gt; 就是「ASCII 中代表數字的字符」的這個集合,也就是 &lt;code&gt;[0123456789]&lt;/code&gt; 這個集合。但,在 Unicode 普及之後,不少正規表示式引擎都將 &lt;code&gt;\d&lt;/code&gt; 這個集合重新定義爲「所有 Unicode 字符屬性爲 Digit 的字符」。 &lt;/p&gt;&lt;p&gt;而 Unicode 既然儘可能地羅列了各種語言用的文字,那各種語言用的數字字符自然也都盡數包含進來了。 &lt;/p&gt;&lt;p&gt;包括了如泰文數字: &lt;/p&gt;&lt;pre&gt;&lt;code&gt;๐ ๑ ๒ ๓ ๔ ๕ ๖ ๗ ๘ ๙&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;或如藏文數字: &lt;/p&gt;&lt;pre&gt;&lt;code&gt;༠ ༡ ༢ ༣ ༤ ༥ ༦ ༧ ༨ ༩&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;不是只有 perl 語言中的 &lt;code&gt;\d&lt;/code&gt; 才這麼寬。 &lt;/p&gt;&lt;p&gt;raku 跟 perl 似乎一樣: &lt;/p&gt;&lt;pre&gt;&lt;code&gt;# raku --version Welcome to Rakudo™ v2024.09. Implementing the Raku® Programming Language v6.d. Built on MoarVM version 2024.09. # raku -e '(^1000000).map(&amp;amp;chr).grep({ /\d/ }).elems.say' 680&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;python 3.12.7 似乎也跟 perl 一樣: &lt;/p&gt;&lt;pre&gt;&lt;code&gt;# python3 --version Python 3.12.7 # echo &amp;quot;import re; print(len([chr(i) for i in range(1000000) if re.match(r'\d', chr(i))]))&amp;quot; | python3 - 680&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Swift 中的 &lt;code&gt;\d&lt;/code&gt; 也會與匹配到 680 個字符: &lt;/p&gt;&lt;pre&gt;&lt;code&gt;# swift -version Swift version 6.0.1 (swift-6.0.1-RELEASE) Target: x86_64-unknown-linux-gnu # swift -e ' import Foundation let digits = (0...999999) .compactMap { UnicodeScalar($0) } .map { String($0) } .filter { $0.range(of: &amp;quot;\\d&amp;quot;, options: .regularExpression) != nil } print(digits.count) ' 680&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;PHP 8 。若用 multi-byte string 及 &lt;code&gt;mb_ereg_match&lt;/code&gt; ,則 &lt;code&gt;\d&lt;/code&gt; 也是 680 個字符: &lt;/p&gt;&lt;pre&gt;&lt;code&gt;# php --version PHP 8.3.13 (cli) (built: Oct 22 2024 18:39:14) (NTS gcc x86_64) Copyright (c) The PHP Group Zend Engine v4.3.13, Copyright (c) Zend Technologies # php -r ' $digits = array_filter(array_map(function($i) { return mb_chr($i, &amp;quot;UTF-8&amp;quot;); }, range(0, 999999)), function($char) { return mb_ereg_match(&amp;quot;\\d&amp;quot;, $char); }); echo count($digits) ' 680&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;node js 與 kotlin (JVM) 的 &lt;code&gt;\d&lt;/code&gt; 看來則是等於 &lt;code&gt;[0123456789]&lt;/code&gt;: (見註1) &lt;/p&gt;&lt;pre&gt;&lt;code&gt;# node --version v20.17.0 # node -e 'console.log( Array.from({length: 1000000}, (_,i) =&amp;gt; String.fromCodePoint(i)).filter(c =&amp;gt; /\d/.test(c)).length )' 10 # kotlin -version Kotlin version 2.0.21-release-482 (JRE 17.0.12+7) ## String(int[], int, int) 是自 unicode codepoint 建構出一個 String 的方法。來自 Java String: https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#String-int:A-int-int- # kotlin -e '(0..999999).map { String(intArrayOf(it), 0, 1) }.filter { Regex(&amp;quot;\\d&amp;quot;).matches(it) }.let { println(it.size) }' 10&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;看來雖然不同語言中 &lt;code&gt;\d&lt;/code&gt; 的意義或許有所不同,並且它仍然代表「由所有數字所構成的集合」,但對於些語言來說,這個集合已經擴張到有包含 Unicode 中的數字而不再是只有 0123456789 這十個數字而已了。 &lt;/p&gt;&lt;p&gt;最後附上在 perl 中, &lt;code&gt;\d&lt;/code&gt; 這個集合的完整列表。 &lt;/p&gt;&lt;pre&gt;&lt;code&gt;# # 印出出所有符合 \d 的字符。 # perl -C7 -E 'my @digits = grep { /\d/ } map { chr($_) } 0..999999; while (@digits) { say join(&amp;quot; &amp;quot;, splice(@digits,0, 10)) }' 0 1 2 3 4 5 6 7 8 9 ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩ ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ ߀ ߁ ߂ ߃ ߄ ߅ ߆ ߇ ߈ ߉ ० १ २ ३ ४ ५ ६ ७ ८ ९ ০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯ ੦ ੧ ੨ ੩ ੪ ੫ ੬ ੭ ੮ ੯ ૦ ૧ ૨ ૩ ૪ ૫ ૬ ૭ ૮ ૯ ୦ ୧ ୨ ୩ ୪ ୫ ୬ ୭ ୮ ୯ ௦ ௧ ௨ ௩ ௪ ௫ ௬ ௭ ௮ ௯ ౦ ౧ ౨ ౩ ౪ ౫ ౬ ౭ ౮ ౯ ೦ ೧ ೨ ೩ ೪ ೫ ೬ ೭ ೮ ೯ ൦ ൧ ൨ ൩ ൪ ൫ ൬ ൭ ൮ ൯ ෦ ෧ ෨ ෩ ෪ ෫ ෬ ෭ ෮ ෯ ๐ ๑ ๒ ๓ ๔ ๕ ๖ ๗ ๘ ๙ ໐ ໑ ໒ ໓ ໔ ໕ ໖ ໗ ໘ ໙ ༠ ༡ ༢ ༣ ༤ ༥ ༦ ༧ ༨ ༩ ၀ ၁ ၂ ၃ ၄ ၅ ၆ ၇ ၈ ၉ ႐ ႑ ႒ ႓ ႔ ႕ ႖ ႗ ႘ ႙ ០ ១ ២ ៣ ៤ ៥ ៦ ៧ ៨ ៩ ᠐ ᠑ ᠒ ᠓ ᠔ ᠕ ᠖ ᠗ ᠘ ᠙ ᥆ ᥇ ᥈ ᥉ ᥊ ᥋ ᥌ ᥍ ᥎ ᥏ ᧐ ᧑ ᧒ ᧓ ᧔ ᧕ ᧖ ᧗ ᧘ ᧙ ᪀ ᪁ ᪂ ᪃ ᪄ ᪅ ᪆ ᪇ ᪈ ᪉ ᪐ ᪑ ᪒ ᪓ ᪔ ᪕ ᪖ ᪗ ᪘ ᪙ ᭐ ᭑ ᭒ ᭓ ᭔ ᭕ ᭖ ᭗ ᭘ ᭙ ᮰ ᮱ ᮲ ᮳ ᮴ ᮵ ᮶ ᮷ ᮸ ᮹ ᱀ ᱁ ᱂ ᱃ ᱄ ᱅ ᱆ ᱇ ᱈ ᱉ ᱐ ᱑ ᱒ ᱓ ᱔ ᱕ ᱖ ᱗ ᱘ ᱙ ꘠ ꘡ ꘢ ꘣ ꘤ ꘥ ꘦ ꘧ ꘨ ꘩ ꣐ ꣑ ꣒ ꣓ ꣔ ꣕ ꣖ ꣗ ꣘ ꣙ ꤀ ꤁ ꤂ ꤃ ꤄ ꤅ ꤆ ꤇ ꤈ ꤉ ꧐ ꧑ ꧒ ꧓ ꧔ ꧕ ꧖ ꧗ ꧘ ꧙ ꧰ ꧱ ꧲ ꧳ ꧴ ꧵ ꧶ ꧷ ꧸ ꧹ ꩐ ꩑ ꩒ ꩓ ꩔ ꩕ ꩖ ꩗ ꩘ ꩙ ꯰ ꯱ ꯲ ꯳ ꯴ ꯵ ꯶ ꯷ ꯸ ꯹ 0 1 2 3 4 5 6 7 8 9 𐒠 𐒡 𐒢 𐒣 𐒤 𐒥 𐒦 𐒧 𐒨 𐒩 𐴰 𐴱 𐴲 𐴳 𐴴 𐴵 𐴶 𐴷 𐴸 𐴹 𑁦 𑁧 𑁨 𑁩 𑁪 𑁫 𑁬 𑁭 𑁮 𑁯 𑃰 𑃱 𑃲 𑃳 𑃴 𑃵 𑃶 𑃷 𑃸 𑃹 𑄶 𑄷 𑄸 𑄹 𑄺 𑄻 𑄼 𑄽 𑄾 𑄿 𑇐 𑇑 𑇒 𑇓 𑇔 𑇕 𑇖 𑇗 𑇘 𑇙 𑋰 𑋱 𑋲 𑋳 𑋴 𑋵 𑋶 𑋷 𑋸 𑋹 𑑐 𑑑 𑑒 𑑓 𑑔 𑑕 𑑖 𑑗 𑑘 𑑙 𑓐 𑓑 𑓒 𑓓 𑓔 𑓕 𑓖 𑓗 𑓘 𑓙 𑙐 𑙑 𑙒 𑙓 𑙔 𑙕 𑙖 𑙗 𑙘 𑙙 𑛀 𑛁 𑛂 𑛃 𑛄 𑛅 𑛆 𑛇 𑛈 𑛉 𑜰 𑜱 𑜲 𑜳 𑜴 𑜵 𑜶 𑜷 𑜸 𑜹 𑣠 𑣡 𑣢 𑣣 𑣤 𑣥 𑣦 𑣧 𑣨 𑣩 𑥐 𑥑 𑥒 𑥓 𑥔 𑥕 𑥖 𑥗 𑥘 𑥙 𑱐 𑱑 𑱒 𑱓 𑱔 𑱕 𑱖 𑱗 𑱘 𑱙 𑵐 𑵑 𑵒 𑵓 𑵔 𑵕 𑵖 𑵗 𑵘 𑵙 𑶠 𑶡 𑶢 𑶣 𑶤 𑶥 𑶦 𑶧 𑶨 𑶩 𑽐 𑽑 𑽒 𑽓 𑽔 𑽕 𑽖 𑽗 𑽘 𑽙 𖩠 𖩡 𖩢 𖩣 𖩤 𖩥 𖩦 𖩧 𖩨 𖩩 𖫀 𖫁 𖫂 𖫃 𖫄 𖫅 𖫆 𖫇 𖫈 𖫉 𖭐 𖭑 𖭒 𖭓 𖭔 𖭕 𖭖 𖭗 𖭘 𖭙 𝟎 𝟏 𝟐 𝟑 𝟒 𝟓 𝟔 𝟕 𝟖 𝟗 𝟘 𝟙 𝟚 𝟛 𝟜 𝟝 𝟞 𝟟 𝟠 𝟡 𝟢 𝟣 𝟤 𝟥 𝟦 𝟧 𝟨 𝟩 𝟪 𝟫 𝟬 𝟭 𝟮 𝟯 𝟰 𝟱 𝟲 𝟳 𝟴 𝟵 𝟶 𝟷 𝟸 𝟹 𝟺 𝟻 𝟼 𝟽 𝟾 𝟿 𞅀 𞅁 𞅂 𞅃 𞅄 𞅅 𞅆 𞅇 𞅈 𞅉 𞋰 𞋱 𞋲 𞋳 𞋴 𞋵 𞋶 𞋷 𞋸 𞋹 𞓰 𞓱 𞓲 𞓳 𞓴 𞓵 𞓶 𞓷 𞓸 𞓹 𞥐 𞥑 𞥒 𞥓 𞥔 𞥕 𞥖 𞥗 𞥘 𞥙 🯰 🯱 🯲 🯳 🯴 🯵 🯶 🯷 🯸 🯹&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;&lt;p&gt;註1:(11/3 更新) &lt;/p&gt;&lt;p&gt;由 &lt;a href="https://timdream.org/"&gt;timdream&lt;/a&gt; 及 &lt;a href="https://taiwan.wtf/@gholk/113414119572750880"&gt;gholk&lt;/a&gt; 來訊指出,在 node js 的範例中若使用 &lt;code&gt;String.fromCharCode(i)&lt;/code&gt; ,其實只會造出 i 在 65535 (0xFFFF) 以下的字,當 i 超過 65535 後會 overflow 而造出某個在 0..65535 這個範圍中的字。因此舊的範例中這段測得 160 的程式碼其實是由於不正確的: &lt;/p&gt;&lt;pre&gt;&lt;code&gt;# node -e 'console.log( Array.from({length: 1000000}, (_,i) =&amp;gt; String.fromCharCode(i)).filter(c =&amp;gt; /\d/.test(c)).length )' 160&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;而舊 kotlin 範例中這段使用了 &lt;a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/to-char.html"&gt;&lt;code&gt;toChar()&lt;/code&gt;&lt;/a&gt; 寫法,也同樣是只會造出 codepoint 範圍在 0..65535 中的字符。因此此範例也是誤導的。 &lt;/p&gt;&lt;pre&gt;&lt;code&gt;# kotlin -e '(0..999999).map { it.toChar() }.filter { Regex(&amp;quot;\\d&amp;quot;).matches(it.toString()) }.let { println(it.size) }' 160&lt;/code&gt;&lt;/pre&gt;</content> <category term="regexp"/> </entry> <entry> <id>https://gugod.org/2024/10/yapc-hakodate-2024/?8016176bbe99ebfae94b3155f100d3d987a64e4e</id> <link rel="alternate" href="https://gugod.org/2024/10/yapc-hakodate-2024/" type="text/html"/> <title>YAPC::Hakodate 2024 之行</title> <published>2024-10-13T20:24:26+08:00</published> <author> <name>gugod</name> </author> <content type="html" xml:base="https://gugod.org">&lt;p&gt;2024 年十月五日,&lt;a href="https://yapcjapan.org/2024hakodate/"&gt;在函館未來大學舉辦的 yapcjapan&lt;/a&gt; 又是一日令人意猶未盡的 YAPC 研討會了。 &lt;/p&gt;&lt;p&gt;&lt;a href="https://www.fun.ac.jp/"&gt;函館未來大學&lt;/a&gt;校園不在函館市區內,而是在北邊的山坡上,一個地勢比較高一些的位置。校園內除了綠地之外,主要的門面是一棟巨大的玻璃建築,那棟建築大約六、七層樓高,約一百餘公尺寬(目測)。但由於位置地勢關係,在函館市區內幾乎都能夠看得到(視線沒被擋到的話)。可能因此,其玻璃牆面上的遮蔭簾基本是拿來做成某種巨大的雙色顯示面板。可讓人在遠遠的函館山上就看得到巨大的 YAPC 四個字。或許依此,我們可以說這是世界最大級的 YAPC 呢。 &lt;/p&gt;&lt;p&gt;&lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/54061575818/in/album-72177720321127841" title="The biggest YAPC, ever."&gt;&lt;img src="https://live.staticflickr.com/65535/54061575818_00e616bcf5.jpg" width="500" height="376" alt="The biggest YAPC, ever."/&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;這次 YAPC 依然是附了一場前夜祭。好像自第一次 YAPC::Asia 開始就有這個前夜祭的會前會。後來每次也都有。也就是說實質上 YAPC 是一個從傍晚開始的研討會啦。 &lt;/p&gt;&lt;p&gt;&lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/54062237541/in/album-72177720321127841/" title="YAPC 前夜祭"&gt;&lt;img src="https://live.staticflickr.com/65535/54062237541_3ff342e565.jpg" width="500" height="376" alt="YAPC 前夜祭"/&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;這次前夜祭的地點不是在函館未來大學,而是是在函館市民會館。這個市民會館位於一個叫做湯川的地區,那地區有不少溫泉飯店。於是就必須趁機,在登入前夜祭之前,先去泡一湯了。隨意找了一間離市民會館很近的溫泉飯店,日歸溫泉 800 日圓。雖然看來設備有些破舊,但至少乾淨,能讓人獲得短暫的休息與滿足。 &lt;/p&gt;&lt;p&gt;這次參與,主要的目的是去發表 &lt;a href="https://perlbrew.pl/Perlbrew-1.00.html"&gt;perlbrew 1.00&lt;/a&gt; 。並且為此準備了 20 分鐘的日語演講。當初徵稿的時候有提示說本次 YAPC 的主題就是未來。於是我就以未來的 perlbrew 會有什麼樣貌為內容主題,點出了 perlbrew 1.00 的釋出,以及其未來會往什麼方向發展過去。 &lt;/p&gt;&lt;p&gt;為了給這次發表做準備而花了不少時間在練習,就沒有仔細讀議程表。但隨意跑堂聽課,還是有聽到一位講者,takamioIO,他做了個 ePBF loader,可用來聽取系統呼叫。顯然這是一個十分有用的 perl 模組。 &lt;/p&gt;&lt;p&gt;&lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/54061355711/in/album-72177720321127841/" title="takemioIO on ePBF loader."&gt;&lt;img src="https://live.staticflickr.com/65535/54061355711_5f6cfcf5ae.jpg" width="500" height="376" alt="takemioIO on ePBF loader."/&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;perlbrew 1.00 內主要追加的內容之一是讓 &lt;a href="https://github.com/skaji/relocatable-perl"&gt;skaji/relocatable-perl&lt;/a&gt; 這個 binary distribution 是直接一步可以裝完的。在 YAPC 會場與其維護者 skaji 簡單談過之後,基本確認了 relocatable-perl 主要目標是要在 Linux 與 macOS 上可以只依賴 glibc 就能執行,並且原則上會持續支援新版的 perl。他認為,讓多數人能夠快速的裝上新版 perl ,對於推陳佈新是十分重要的。我完全同意:既然 perl 本身的更新都已經是每個月都出小版本,每年都出大版本的步調了,那就更有必要讓使用者們能夠以一樣的步調來把握新版的內容才行。 &lt;/p&gt;&lt;p&gt;目前對 skaji/relocatable-perl 的支援算是實驗性質的,算是先丟給使用者試用看看,並且蒐集意見。基本上只要 skaji 本人持續提供維護,我也打算同步提供支持。目前尚無把它當成預設安裝選項的打算,但,未來的確是打算讓 perlbrew 預設安裝是直接裝可執行檔,不再原始碼開始編譯。畢竟這樣子對於使用者而言更加的便利。 &lt;/p&gt;&lt;p&gt;由於函館未來大學位於市郊外,公共交通不便,主辦單位這次特地安排了可往來於JR函館車站與未來大學校門口的遊覽車,早晚各一班。讓像我這種在函館市當地沒有交通工具的人至少可以順利前往研討會,也能順利離開。同時,午餐則是與當地業者合作,除了提供當地便當與幸運小丑漢堡數十個,還請來了三輛餐車提供現做的熱食與甜點。 &lt;/p&gt;&lt;p&gt;幸運小丑漢堡是函館當地著名的漢堡店,在市區內分店衆多,但是每一間基本上都是時常滿座的。提供給 YAPC 與會者的份也是一瞬間就被拿完了。我在後日找個不必排隊的時段再到店面吃了一顆荷包蛋漢堡配烏龍茶。出了函館,這世界上還有什麼其他城市內的漢堡店能讓人吃到荷包蛋漢堡配烏龍茶的組合套餐? &lt;/p&gt;&lt;p&gt;未來大學除了校園主建築物令人吃驚之外,校內的硬體設施也是優秀無比。建築物明亮開放之外,教室內每一組課桌椅都配有專用的電源插座與 RJ45 網路線頭給學生來用。雖然不確定有多少學生會實際使用有線網路(或許不少),顯然這教室的規格已經完全是以學生會在課堂上使用個人電腦設備來輔助學習爲前提而定義出來的了。除了這項優秀的規格之外,這學校持有的網域爲 &lt;code&gt;fun.ac.jp&lt;/code&gt;。校名縮寫爲 &lt;code&gt;fun&lt;/code&gt;,那鐵定表示在校內所有的學習都是 &lt;code&gt;-Ofun&lt;/code&gt; (Optimized for fun ) 了。(笑) &lt;/p&gt;&lt;p&gt;除了「前夜祭」這會前會之外,這次還有一些吃飯喝酒之類會後會,但其中最吸引我的一項是 &lt;a href="https://connpass.com/event/326666/"&gt;YAPC函館市電LT&lt;/a&gt; 。這是 Y.pm 主催,包下了函館路面電車一輛,從「函館市企業局交通部」(車庫)出發,開往函館車站前方向。在電車上讓人做閃電講,並且每個人的時間限制是三站區間內。可惜我在得知有這個活動的時候,就已經報名超額了。並且由於場地就是路面電車車輛,有很明顯的容積限制的關係,在已經超額的狀況之下是絕對不可能硬擠進去然後縮在角落聽的。無論是有多想在滿員電車狀態下聽課都會被電車車殼這個物理結界給擋在外面。只是這個結合了當地特色形式的研討會附加活動真的是太有意思了,也讓人知道:原來路面電車是可以租借下來的啊。 &lt;/p&gt;&lt;p&gt;這麼回想起來,2023 年京都那次呈現出來的是一種「宗教感」,而 2024 年這兩次結合了當地特色、美食、還配上遊覽車接送,讓人有機會能在車上與其他與會者交談(只差沒唱卡拉OK了),這些做法綜合起來就是營造出一種「觀光感」啊。 &lt;/p&gt;&lt;p&gt;那這麼說來這篇部落格記事到底是屬於技術雜記類,還是觀光類?那就都是了吧。最後附上填充內容用的觀光照片作爲結尾。 &lt;/p&gt;&lt;p&gt;&lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/albums/72177720321127841" title="YAPC::Hakodate 2024"&gt;&lt;img src="https://live.staticflickr.com/65535/54061315458_3a690d2efb.jpg" width="500" height="375" alt="YAPC::Hakodate 2024"/&gt;&lt;/a&gt;&lt;script async src="//embedr.flickr.com/assets/client-code.js" charset="utf-8"&gt;&lt;/script&gt;&lt;/p&gt; </content> </entry> <entry> <id>https://gugod.org/2024/09/twostack-wm-and-hammerspoon/?595bc4166311135228ab44edd93567d9cd74696a</id> <link rel="alternate" href="https://gugod.org/2024/09/twostack-wm-and-hammerspoon/" type="text/html"/> <title>TwoStackWM 與 Hammerspoon</title> <published>2024-09-14T13:51:34+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>最近花了一些時間在試用一些於 macOS 上提供所謂 tiling window management 的軟體。 </p> <p>比較有名的是這三家: </p> <ul> <li>Amythest </li> <li>AeroSpace </li> <li>yabai + shkd </li> </ul> <p>綜合來說,Amythest 算是夠好用,也很好裝(相對於其他兩者而言)。但是對於我而言總是有一些不夠,或是很難搞的地方。 </p> <p>我花了點時間稍微定義了一下於我而言必要的「視窗管理機能」,大約是以下這幾項: </p> <ol> <li>所有功能皆能夠定義在快速鍵上。如果按一個快速鍵可以依序發動多重功能更爲理想。例如:按 Hyper-Q 後先將 Slack 關掉,再將 Zoom 關掉。 </li> <li>提供快速切換到特定視窗的能力。例如:按 Hyper-e 後切換到現在開著的 Emacs。 </li> <li>提供「將視窗最大化」及「將最大化的視窗變成不是最大化」 </li> <li>基本上將畫面上幾個視窗以平鋪的方式同時顯示出來,但最多顯示兩三個視窗就好。 </li> <li>能將畫面分成左右兩區,分爲「主要區」與「側邊區」。能讓我將較需要空間的視窗放在主要區,而側邊區則是放一些偶爾需要,但是不會一直需要的視窗。 </li> <li>主要區與側邊區的大小比例可以讓我調整,但不要讓我常常花時間在調整。 </li> </ol> <p>「主要區」與「側邊區」的這種區分概念主要是在用過 xmonad 與 dwm 後帶過來的,比起要經常決定「要把目前這個視窗放在螢幕上的哪個區象限」,以「把目前這個視窗移動去主要區或是側邊區」這種方式來簡化管理難度,對我而言更加合適。 </p> <p>在釐清了自己的需求之後,很容易就可以發現到之前試過的幾個 tiling window manager 都不夠用了。於是只好自己找工具湊合看看了。 </p> <p>在定義快速鍵方面,有找到 <a href="https://zenangst.github.io/app/keyboardcowboy/index.html">Keyboard Cowboy</a> 這個能讓人自定自動化工作流程,並將工作流程綁在快速鍵上的工具。能滿足我上述需求列表中的第一點及第二點。 </p> <p>在視窗管理方面,雖然沒有找到能直接滿足我需求的軟體,但找到了 <a href="https://www.hammerspoon.org/">Hammerspoon</a> 這個工具。這個工具能讓人以 lua 程式語言來自己寫一套 tiling window manager 出來。於是我立刻就自己寫了一套試試。名爲 <a href="https://github.com/gugod/TwoStackWM.spoon">TwoStackWM</a>。 </p> <p>這個 TwoStackWM 只提供六個能將目前焦點視窗移動到別處的函數: </p> <ul> <li><code>moveFocusedWindowToMainStack()</code> -- 移動到主要區 </li> <li><code>moveFocusedWindowToSideStack()</code> -- 移動到側邊區 </li> <li><code>maximizeFocusedWindow()</code> -- 最大化 </li> <li><code>toggleFocusedWindowToMainOrSide()</code> -- 在主要區與側邊區兩狀態間切換 </li> <li><code>toggleFocusedWindowToMaxOrMainOrSide()</code> -- 在最大、主要區與側邊區三中狀態中切換 </li> <li><code>moveFocusedWindowToNextScreen()</code> -- 移動到下一個螢幕 </li> </ul> <p>而主要區與側邊區的大小比例,則是在設定當中一次性寫好的。無法動態調整。也就是說我可花一次時間將其調整到大致順眼的比例,然後就再也不必管了。 </p> <p>TwoStackWM 並不會把所有視窗一次顯示出來。而是最多只會顯示兩個,一主一側。要切換焦點就使用 macOS 原生、改不掉的 <code>Cmd-Tab</code> 快速鍵,使其成爲視窗堆疊中最上層的就好。 </p> <p>Hammerspoon 提供的函數十分直覺好用。並且,它也提供了一個 Console 可以讓人立刻執行一段 lua 程式碼。十分便於開發。能過讓我以不到 100 行的程式碼就定義出能符合自己需求的 Window Manager出來。 </p> <p>目前還沒摸索出如何以 Hammerspoon 取代 Keyboard Cowbody 提供的工作流程功能。但想必一定程度上也是做得到的。 </p> </div> </content> <category term="software"/> </entry> <entry> <id>https://gugod.org/2024/06/perlclass-first-explore-monty-hall-game-simulation/?d6cf57f1a75e2a43d3868af51c9ab5a2cefd9751</id> <link rel="alternate" href="https://gugod.org/2024/06/perlclass-first-explore-monty-hall-game-simulation/" type="text/html"/> <title>perlclass 初探: 以模擬 Monty Hall Problem 為例</title> <published>2024-06-09T23:01:41+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>Monty Hall Problem (<a href="https://zh.wikipedia.org/zh-tw/%E8%92%99%E6%8F%90%E9%9C%8D%E7%88%BE%E5%95%8F%E9%A1%8C">蒙提霍爾問題</a>)是個奇妙而有趣的數學遊戲問題。維基百科上提供的問題本文為: </p> <blockquote> <p>假設你正在參加一個遊戲節目,你被要求在三扇門中選擇一扇:其中一扇後面有一輛車;其餘兩扇後面則是山羊。你選擇了一道門,假設是一號門,然後知道門後面有什麼的主持人,開啟了另一扇後面有山羊的門,假設是三號門。他然後問你:「你想選擇二號門嗎?」轉換你的選擇對你來說是一種優勢嗎? </p> </blockquote> <p>此問題的解答是「會」,也就是換答案後會比較容易得到汽車的意思。 </p> <p>但,這答案是以列舉出幾種狀況的機率來比較而得的。以機率而論,如果我能玩這遊戲 1000 次,那麼每一局都依主持人提供的資訊來更換答案後,我能在這 1000 局內獲勝的總次數較多。期望值約為 1000 <em> 2/3,也就是約為 666 次。而如果我每一局都不換答案,那我在這 1000 局內的獲勝期望值則為 1000 </em> 1/3,也就是約為 333 次。 </p> <p>既然如此,那就必須寫個程式來模擬看看了。以下是 <a href="https://github.com/gugod/bin/blob/master/play-monty-hall.pl">play-monty-hall.pl</a> ,以 <a href="https://perldoc.perl.org/perlclass">perlclass</a> 提供的新語法寫成的一個模擬程式,可模擬兩種策略玩家在玩了多局之後的勝率。雖然沒有註解,但應該還算是能夠望文生義的程度。 </p> <pre> <code>#!/usr/bin/env perl use v5.38; use feature 'class'; no warnings 'experimental::class'; class Game { field $doors :param; field $winningDoor = 1 + int rand($doors); method doors { $doors } method winningDoor { $winningDoor } method loosingDoors { grep { $_ != $winningDoor } (1..$doors); } }; class FirstChoicePlayer { field $doors :param; field $firstChoice = 1 + int rand($doors); field @loosingDoors; method doors { $doors } method addLoosingDoors ($n) { push @loosingDoors, $n } method loosingDoors () { @loosingDoors } method firstChoice () { $firstChoice } method finalChoice () { $firstChoice } }; class ChangeChoicePlayer :isa(FirstChoicePlayer) { method finalChoice () { my %isLoosing = map { $_ =&gt; 1 } $self-&gt;loosingDoors(); my @choices = grep { $_ != $self-&gt;firstChoice() } grep { ! $isLoosing{$_} } 1..$self-&gt;doors(); die "Illegal state" if @choices != 1; return $choices[0]; } }; class GameMaster { field $doors :param; method playWith ($player) { die "No player ?" unless defined $player; my $game = Game-&gt;new( doors =&gt; $doors ); my %untold = map { $_ =&gt; 1 } ($game-&gt;winningDoor, $player-&gt;firstChoice); while ((keys %untold) == 1) { my $door = 1 + int rand($doors); $untold{$door} = 1; } my @revealLoosingDoors = grep { ! $untold{$_} } (1..$doors); for my $door (@revealLoosingDoors) { $player-&gt;addLoosingDoors($door) } my $finalChoice = $player-&gt;finalChoice(); return $finalChoice == $game-&gt;winningDoor; } }; sub playOneRound($playerClass) { my $doors = 3; my $gm = GameMaster-&gt;new( doors =&gt; $doors ); my $player = $playerClass-&gt;new( doors =&gt; $doors ); return $gm-&gt;playWith( $player ); } sub play ($rounds, $playerClass) { my $wins = 0; for (1 .. $rounds) { my $win = playOneRound($playerClass); $wins++ if $win; } return $wins; } sub sim ($rounds) { for my $playerClass ("FirstChoicePlayer", "ChangeChoicePlayer") { my $wins = play($rounds, $playerClass); my $pWin = $wins / $rounds; say "$playerClass wins $wins / $rounds. p(win) = $pWin"; } } sim(shift // 1000); </code> </pre> <p>可以提供一個參數,表示要模擬幾局。預設為 1000 局。執行起來如下: </p> <pre> <code># play-monty-hall.pl FirstChoicePlayer wins 323 / 1000. p(win) = 0.323 ChangeChoicePlayer wins 665 / 1000. p(win) = 0.665 # play-monty-hall.pl 1000000 FirstChoicePlayer wins 333606 / 1000000. p(win) = 0.333606 ChangeChoicePlayer wins 666348 / 1000000. p(win) = 0.666348</code> </pre> <p>這程式內主要幾個互相作用的 class: </p> <ul> <li><code>FirstChoicePlayer</code>: 以不變為其策略的玩家 </li> <li><code>ChangeChoicePlayer</code>: 以改變為其策略的玩家 </li> <li><code>GameMaster</code>: 與玩家互動的遊戲主持人。 </li> <li><code>Game</code>: 維護單一一局的遊戲初始資訊。基本上只有記住哪號門是贏門 (<code>$winnigDoor</code>),並提供列舉出所有輸門的方法 <code>loosingDoors</code> </li> </ul> <p>Game 物件在建構、初始完畢後計基本上是個常數了,沒有什麼特別的地方。 FirstChoicePlayer 也差不多,只是會有個 <code>@loosingDoors</code> 內部狀態來記著那些由 GameMaster 提供的輸門號碼。 </p> <p>而此處我讓 <code>ChangeChoicePlayer</code> 為 <code>FirstChoicePlayer</code> 的延伸,依照 <code>$self-&gt;firstChoice</code> 與 <code>$self-&gt;loosingDoors</code> 的內容來推算出 <code>finalChoice</code>。這邊我原本以為透過繼承機制,<code>FirstChoicePlayer</code> 的兩個 <code>field</code> 變數都可以直接在 <code>ChangeChoicePlayer</code> 內來使用。但結果是不行,必須在透過 <code>FirstChoicePlayer</code> 內定義的 getter method 才行。這表示由 <code>field</code> 所定義出來的便是是私有於該類別而已。 </p> <p>在所有類別中有一項共同參數 <code>$doors</code>,也就是這遊戲的門的數量。<code>Game</code> 類別是依 <code>$doors</code> 來隨機生成出贏門的號碼。兩個玩家類別內則是以數字去隨機產生 <code>firstChoice</code>。<code>GameMaster</code> 類別則是以此資訊來建構先的 <code>Game</code> 物件,還有推算出能告訴玩家哪些門是輸門。這邊我用了 <code>:param</code> 這個添在 <code>field</code> 變數上的屬性 (<code>field $doors :param;</code>),來代表說這 <code>field</code> 的值必須被提供給類別的建構函式 <code>new</code>。這用法尚算直覺。而其他依賴 <code>$doors</code> 的值所計算出來的各 <code>field</code> 都似乎是正確地在物件建構時期被計算完畢了。無須另外調整。 </p> <p>目前幾個有需要用到的 getter method 都是我自己手動補上的,讓程式碼看來量很多。但依 <a href="https://perldoc.perl.org/perlclass#TODO">perlclass 文件中 TODO 一節</a> 內的說明,看來以後能寫個 <code>:reader</code> 來讓 perl 自動生成出 getter method。就能省下不少打字的力氣。 </p> <p>雖然 perlclass 語法跟類別機能十分基本,比不上其他以物件導向為核心設計的語言。但以這個小程式的用途用起來沒意外,很夠用。等以後改版之後再來看看有沒有什麼更有意思的地方。 </p> </div> </content> <category term="perl"/> </entry> <entry> <id>https://gugod.org/2024/03/manage-dotfiles-with-gnu-stow/?96f538bd9a270738320af3d482610c8484b0db87</id> <link rel="alternate" href="https://gugod.org/2024/03/manage-dotfiles-with-gnu-stow/" type="text/html"/> <title>以 GNU Stow 來管理 dotfiles</title> <published>2024-03-04T23:33:40+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>最近發現 <a href="https://www.gnu.org/software/stow/">GNU Stow</a> 這個軟體,其主要提供的功能是以 symlink 來做到軟體安裝。其自我介紹文中第一段話為: </p> <pre> <code>GNU Stow is a symlink farm manager which takes distinct packages of software and/or data located in separate directories on the filesystem, and makes them appear to be installed in the same place. </code> </pre> <p>意思就是說:你可以用 GNU Stow 把本來裝在四處的資料或程式,以 symlink,讓它們看來好像是全裝在同一個目錄下。 </p> <p>乍看之下好像怪怪的沒有什麼用處(為何不一開始就裝在一起?)但轉念一想:這不就是 <a href="https://brew.sh/">homebrew</a> 的做法嗎? </p> <p>看來 GNU Stow 所做的工作,就類似於 <code>brew link</code> 這個階段,把本來安奘在 A 處的各個檔案,逐一在 B 處建立相對應的 symlink。由於 B 處都是 symlink,要移除也相對簡單。並且,能以 symlink 內容作為某種安裝證明,不怕失誤刪到了不在管轄範圍內的物件。 </p> <p>這做法對於管理 <code>$HOME</code> 底下的 dotfile 十分有用。由於 dotfile 都是必須要放在 <code>$HOME</code> 底下指定位置的檔案,如果要以版本控制系統來管理,那就還要另外有一套方式去把那些檔案自版本控制系統中拷貝出來放在 <code>$HOME</code> 底下,如果還想要有簡單的同步或刪除機制的話,用 GNU Stow / symlink 似乎就很適合了。 </p> <p>以下用幾個簡單的範例來示範一下。首先是建一個 dotfiles/ 目錄,並在底下依照軟體名建立出若干子目錄。子目錄底下則是放置該軟體的 dotfile。並且,使其中 dotfile 路徑有保留住 <code>$HOME</code> 之後的部分。例如,如果某 abc 軟體的 dotfile 為 <code>$HOME/.config/abc/abc.conf</code>,那就把其 <code>$HOME</code> 的部分換為 <code>dotfiles/abc/</code>。也就是要建出 <code>dotfiles/abc/.config/abc/abc.conf</code>。 </p> <p>如果是從既有的檔案移管,準備起來大致上像這樣: </p> <pre> <code>mkdir -p dotfiles/zsh cp ~/.zshrc ~/.zshenv dotfiles/zsh/ mkdir -p dotfiles/emacs/.emacs.d cp ~/.emacs.d/init.el dotfiles/emacs/.emacs.d mkdir -p dotfiles/sway/.config/sway/ cp ~/.config/sway/* dotfiles/sway/.config/sway/ mkdir -p dotfiles/wezterm/.config/wezterm/ cp ~/.config/wezterm/* dotfiles/wezterm/.config/wezterm/</code> </pre> <p>將 <code>dotfiles/</code> 準備完畢之後,就執行 <code>stow</code> </p> <pre> <code>cd dotfiles stow --target=$HOME zsh/ stow --target=$HOME emacs/ stow --target=$HOME sway/ stow --target=$HOME wezterm/</code> </pre> <p>這麼一做完之後,原本 <code>$HOME</code> 底下的 dotfile 就會被 stow 改成是連到 <code>dotfiles/</code> 目錄底下某個檔案的 symlink 了。 </p> <p>而 <code>dotfiles/</code> 目錄本身就可以再透過 <code>git init</code> 等步驟來納入版本控制系統中,並且,其內容是依照各個軟體名分類放好了的。就算實際在 <code>$HOME</code> 底下會出現在很多子目錄,但在版本控制系統中是很一致的。 </p> <p>特別是在刪除的時候。有時候試用軟體要寫幾個 dotfile,一陣子沒用後,把軟體刪除了,但 dotfile 卻沒有一起清。久而久之就忘了那些在 <code>$HOME</code> 底下的 <code>.abcrc</code>、<code>.xyz.conf</code> 倒底是有用還是已經沒用的了。變得想清理又會怕弄錯。 </p> <p>透過本文所述的管理方式,如果哪天想把軟體 abc 的 dotfile 全丟了,也不必再花心力去找出它的 dotfile 是 <code>.abcrc</code>、<code>.abc.conf</code>、<code>config/abc/abc.conf</code> 還是什麼其他冷門的命名慣例,只要以 stow 指令: </p> <pre> <code>stow --target=$HOME --delete abc/</code> </pre> <p>就可以把當初安裝上的所有檔案一次清光了。 </p> <p>如果發現不小心刪錯了,再重跑一次 <code>stow</code> 就可以救回來。 </p> <p>GNU Stow 的機制簡單又合理。看來應該能讓管理個人的 dotfile 的過程變得更有條理一些。 </p> </div> </content> <category term="software"/> </entry> <entry> <id>https://gugod.org/2024/02/yapc-hiroshima/?6ae81d7ea6f7f642f3cad0128831d1e30c53eddb</id> <link rel="alternate" href="https://gugod.org/2024/02/yapc-hiroshima/" type="text/html"/> <title>YAPC::Hiroshima 2024 之行</title> <published>2024-02-14T22:01:13+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>這一次的 YAPC Japan 是辦在廣島國際會議中心,位於和平紀念公園內,離原爆圓頂館很近。雖然離市中心區有一小段距離,但走起來並不算遠。 </p> <p>比起去年的 YAPC::Kyoto,這次的活動規模似乎擴大了。贊助商數竟然超過 50 家,而且有八間是廣島當地的中小企業。這還真是令人驚訝。 </p> <p>不過這次的議程,在內容方面與 Perl 直接相關的已經減少到一半左右了,可能算是有些偏離主體?但儘管如此,技術方面的主題仍然挺吸引人,並且技術知識的共享方面是共通的。似乎可以不必計較。 </p> <p>贊助商的攤位方面,有十來間到場設攤宣傳的廠商。另我印象比較深刻的是 chocoZAP 這個主打用零碎時間來運動的輕度健身的品牌,竟然也是贊助商(其公司為 RIZAP)。而且也在現場招募。從宣傳單上看來,伺服器端是 Ruby,iOS App 為 Swift,Android 為 Kotlin 這樣的組合吧。宣傳單的背面則是拉人加入健身房會員的廣告了(附折扣碼)(笑)。 </p> <p>另一間另我印象深刻的是 Findy。其主產品是協助軟體團隊能理解開發現況的視覺化輔助工具。跟我在碩士班期間做的題目很像。能給一個團隊一些簡明的圖表來迅速看出目前專案開發的狀態,瓶頸之有無,人員協作的連結度等等。應該比較偏向是給管理階級的人員看的圖資工具。 </p> <p>議程本體方面,總共分成三軌,自然也是等日後看有沒有錄影可以補完。在此先大致上摘要了一些我現場聽到覺得有意思的內容。 </p> <p>〈VISAカードの裏側と “手が掛かる” 決済システムの育て方 by 三谷〉。講者是在 VISA 發卡公司員工。這演講算是業界甘苦談吧。難度核心部份在於要能夠「寬鬆而有彈性地」去處理由 VISA API 呼過來的各種不太合理的內容。講者宣稱在聽完後,大家之後必定會在拿到刷卡對帳單時好好看一下在那張小單據印上的各欄資訊。這是真的。 </p> <p>〈rakulangで実装する! RubyVM by 八雲アナグラ〉。講者探索了如何以 rakulang 製作一個簡單的 Ruby VM,並分享了其摘要。嚴格說起來他做的程式不算是 Ruby VM,因為不能吃 bytecode,只能吃文字格式的組語。但要做出 YARV bytecode 似乎不那麼容易,所以就退而求其次了。是深入淺出,內容豐富的演講。 </p> <p>〈PerlでつくるフルスクラッチWebAuthn/パスキー認証 by macopy〉。講者用 live coding 形式說明了 WebAuthn 協定。概要清晰,有把 WebAuthn 中幾個重點都解釋出來。live coding 最後也成功了。但看來有 80% 左右的程式碼是 Copilot 寫的啊。 (結果 ok 就好) </p> <p>Keynote 由「とほほのWWW入門」這個網站的作者「杜甫々」來登台。看來是位人人皆知的名人,這網站上所有文件似乎都是他自己編寫的,種類眾多,從軟體技術細節到所得稅法都有著墨。真是不得由衷讓人欽佩:怎麼會有人這麼會寫文件? </p> <p>伴隨研討會的舉行,同時這次由面白法人主催了個 perlgolf 活動。很久沒玩了,還是頂懷念這種看似胡搞,但卻又能確實達成目的且節節變難的重構過程啊。同時也有種:「這才是 Perl 研討會啊!」的一種爽快感。雖然實務上不會有要把程式碼節節縮短的需要,但對同一個問題反覆進行重構、不斷得出不同風格的解法,不也是一種解決問題所必備的基礎能力嗎? </p> </div> </content> <category term="yapcjapan"/> <category term="hiroshima"/> <category term="perl"/> </entry> <entry> <id>https://gugod.org/2023/12/perl-5-38-2-5-36-3-5-34-3-released/?aaea9add779636c7a9b58baf1d5861af0026cac7</id> <link rel="alternate" href="https://gugod.org/2023/12/perl-5-38-2-5-36-3-5-34-3-released/" type="text/html"/> <title>perl 5.38.2、5.36.3、5.34.3 三個版本的釋出</title> <published>2023-12-03T10:12:43+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>最近注意到有三個新版連發: </p> <ul> <li><a href="https://metacpan.org/release/PEVANS/perl-5.38.2/changes">https://metacpan.org/release/PEVANS/perl-5.38.2/changes</a> </li> <li><a href="https://metacpan.org/release/PEVANS/perl-5.36.3/changes">https://metacpan.org/release/PEVANS/perl-5.36.3/changes</a> </li> <li><a href="https://metacpan.org/release/PEVANS/perl-5.34.3/changes">https://metacpan.org/release/PEVANS/perl-5.34.3/changes</a> </li> </ul> <p>但是內容都一樣,看來是專門為了處理以下兩個 CVE 而發的新版本: </p> <ul> <li>CVE-2023-47038 - Write past buffer end via illegal user-defined Unicode property </li> <li>CVE-2023-47039 - Perl for Windows binary hijacking vulnerability </li> </ul> <p>CVE-2023-47038 的影響範圍是自 5.30.0 (釋出日為 2019/05/22) 到 5.38.0 (釋出日為 2023/07/02)。這範圍不小,得來升級一下。 </p> </div> </content> <category term="perl"/> </entry> <entry> <id>https://gugod.org/2023/11/notes-about-sway-fcitx5/?ad7e225038323934a493ad06239da7cdb5edeee5</id> <link rel="alternate" href="https://gugod.org/2023/11/notes-about-sway-fcitx5/" type="text/html"/> <title>Fedora Linux Sway 桌面環境變數設置</title> <published>2023-11-21T00:51:39+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>在 Fedora Linux 上,要裝設 <a href="https://swaywm.org/">Sway</a> 的方式是裝 Sway Desktop 這一組套件: </p> <pre> <code>dnf group install 'Sway Desktop' </code> </pre> <p>這麼做完之後,在 GDM 登入畫面內某個不起眼的選單內底就可以選擇使用 Sway。 </p> <p>但只是這樣的話,有一些需要在 sway 啟動前就設定好的環境變數似乎就無法可設。主要是這些: </p> <pre> <code>MOZ_ENABLE_WAYLAND=1 INPUT_METHOD=fcitx GTK_IM_MODULE=fcitx QT_IM_MODULE=fcitx XMODIFIERS=@im=fcitx </code> </pre> <p>稍微找了一下,發現透過 gdm 開的 sway,似乎是叫做 <code>start-sway</code> </p> <pre> <code># pgrep -lfa gdm 1208 /usr/sbin/gdm 2011 gdm-session-worker [pam/gdm-password] 2151 /usr/libexec/gdm-wayland-session --register-session start-sway </code> </pre> <p>在 <code>/usr/share/wayland-sessions/sway.desktop</code> 中也可看到這行: </p> <pre> <code>Exec=start-sway </code> </pre> <p>在 <code>/etc</code> 搜尋 <code>start-sway</code> 這個字串的話,可看到 <code>/usr/bin/start-sway</code> 這檔名出現在 <code>/etc/sway/environment</code> 內。 </p> <pre> <code># sudo rg start-sway /etc/ /etc/sway/environment 2:# from /usr/bin/start-sway script for all users of the system. </code> </pre> <p><code>/usr/bin/start-sway</code> 這個檔案是個 shell script,讀其程式碼後發現它的主要作用是去讀取 <code>/etc/sway/environment</code> 及 <code>${HOME}/.config/sway/environment</code> 的內容,吃進這兩檔案內所設好的變數之後,再啟動 sway。 </p> <p>看來正好能滿足我的需要。於是將一干變數塞入 <code>${HOME}/.config/sway/environment</code> 後,登出、重新登入。就管用了。 </p> <p>我猜 <code>start-sway</code> 這 shell scrett 是 Fedora Linux 方面對設定環境變數這需求所實做出的一個變通方法。 </p> <p>目前使用 Sway 主要的問題之一,是在只支援 Wayland 的幾個應用程式視窗內進行打字時,雖可看到輸入的「預編輯」有正確地內嵌在應用程式中,但是選字窗則是完全消失,毫無蹤影。 </p> <p>不少通 Wayland 協定的終端機類程式,如 foot、WezTerm 等等,皆是能打字,但選字窗看不到。反而,那些需透過 XWayland 才能執行的程式,像是 lxterminal 跟 Emacs 就能打字,能看到選字窗: </p> <p>依 <a href="https://github.com/fcitx/fcitx5/issues/206#issuecomment-762958441">@wengxt 在 Fcitx5 專案中所留之言</a>,不見選字窗,是因為 Sway 卻乏幾項關於 <a href="https://wayland.app/protocols/input-method-unstable-v1">input_panel 協定</a>之實作,而讓 fcitx5 無法得知該將選字窗繪製在何處。 </p> <p>依照 <a href="https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland#Sway">fcitx5 wiki Using_Fcitx_5_on_Wayland#Sway</a> 這一頁中簡短的說明看來,似乎已經有一解 <a href="https://github.com/swaywm/sway/pull/7226">Sway PR 7226</a> 待併入 Sway 之中。雖然仍需等待,但總之,各類程式都有替代方案,因此都算可用。 </p> </div> </content> <category term="linux"/> <category term="swaywm"/> </entry> <entry> <id>https://gugod.org/2023/10/masked-private-email-address/?819d456f6a3b83c3f2cfcb662ec32dc7c81b064e</id> <link rel="alternate" href="https://gugod.org/2023/10/masked-private-email-address/" type="text/html"/> <title>masked / private email 服務</title> <published>2023-10-19T23:47:29+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p><a href="https://www.fastmail.help/hc/en-us/articles/4406536368911-Masked-Email">https://www.fastmail.help/hc/en-us/articles/4406536368911-Masked-Email</a> </p> <p>基本上是把多個自動生成的 email 地址對應自己的信箱的轉寄服務。這自動生成的 email 地址通常看來就像是串不好唸的咒文。 </p> <p>賣點就是匿名性。如果有什麼網站資料被竊盜的問題發生時,可以立刻把流出去的那個 email 地址給撤銷掉,讓它變成無效的。(從這點看來,自動生成的演算法必 須要類似 UUID 那樣,既不太容易列舉、又絕對不會生出重複的字串。) </p> <p>原則上是每個站都給不同的 email 地址會比較好管理。 </p> <p>像在 Usenet group 這種公開場所,基本上必須在 From 欄位內給出自己的 email 給所有人看。顯然也很適合來使用這種 email 地址。 </p> <p>現在有一些 Usenet group 上的人會故意在 From 內的 Email 地址處提供像 `john@ex{amp]le.com' 這種不合規格的字串,也算是個方法。由於 hostname 部分 解不出來,至少能防到一些爬資料的機器人。但有智慧的物種則有機會看穿這種 email 地址的用意而在必要時手動修正一下。只是或許有被 NNTP 伺服器擋掉,或 是造成處理失誤等可能性。 </p> <p>另外想到有 <a href="https://simplelogin.io/">https://simplelogin.io/</a> 這個服務。基本上是一樣的,但 simplelogin 只有提供轉寄,而 fastmail 主要是提供 email 信箱。 </p> <p>還有 <a href="https://duckduckgo.com/email/">https://duckduckgo.com/email/</a> Duckduckgo 那裡也有提供類似的,他們叫做 "Private Duck Address"。似乎可以一直產生新的。但是必須先去申請一個 @duck.com 的 email 地址下來,然後這個 email 地址也只是轉寄到現有信箱。 </p> <p>proton mail 那邊好像還沒有這做到這種地步,不知是否有機會跟進。 </p> </div> </content> <category term="email"/> </entry> <entry> <id>https://gugod.org/2023/08/howto-enable-ibus-mozc-hiragana-mode-by-default/?3990695459e8565f3896d4464500aa61f9d45d66</id> <link rel="alternate" href="https://gugod.org/2023/08/howto-enable-ibus-mozc-hiragana-mode-by-default/" type="text/html"/> <title>如何讓 ibus mozc 直接進入平假名模式</title> <published>2023-08-04T10:49:06+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>ibus mozc 的預設輸入模式叫做 "Direct Input",也就是「不是日文輸入」的意思。依照預設熱鍵設定看來,似乎是為了能讓人使用鍵盤上的「變換」鍵來快速於「英數」與「平假名」兩種輸入模式間切換。但對於使用多種輸入法的人來說,變成要在切換到 mozc 後還要再多按一次變換鍵才能開始打平假名,反而礙事。 </p> <p>要讓 ibus mozc 的預設模式為平假名的辦法,是去修改 <code>.config/mozc/ibus_config.textproto</code>,讓 <code>active_on_launch</code> 為 <code>True</code>: </p> <pre> <code>active_on_launch: True</code> </pre> <p>改完後重新開機。 </p> <p>順帶附上整個檔內容如下,以供參考: </p> <pre> <code># `ibus write-cache; ibus restart` might be necessary to apply changes. engines { name : "mozc-jp" longname : "Mozc" layout : "default" layout_variant : "" layout_option : "" rank : 80 symbol : "&amp;#x3042;" } engines { name : "mozc-on" longname : "Mozc:&amp;#x3042" layout : "default" layout_variant : "" layout_option : "" rank : 99 symbol : "&amp;#x3042;" composition_mode : HIRAGANA } engines { name : "mozc-off" longname : "Mozc:A_" layout : "default" layout_variant : "" layout_option : "" rank : 99 symbol : "A" composition_mode : DIRECT } active_on_launch: True</code> </pre> </div> </content> <category term="mozc"/> <category term="ibus"/> </entry> <entry> <id>https://gugod.org/2023/07/tprc-2023-toronto/?504bee37be29f906670e69cce7256c2a9bcd08e5</id> <link rel="alternate" href="https://gugod.org/2023/07/tprc-2023-toronto/" type="text/html"/> <title>TPRC 2023 與多倫多之旅</title> <published>2023-07-17T19:59:31-04:00</published> <author> <name>gugod</name> </author> <content type="html" xml:base="https://gugod.org">&lt;p&gt;TPRC 2023 Toronto 的錄影已陸續釋出,可於 youtube 上觀看: &lt;a href="https://www.youtube.com/playlist?list=PLA9_Hq3zhoFwrDiojWd_lFUaOHlsUUEJa"&gt;https://www.youtube.com/playlist?list=PLA9_Hq3zhoFwrDiojWd_lFUaOHlsUUEJa&lt;/a&gt; &lt;/p&gt;&lt;p&gt;TPRC -- The Perl and Raku Conference. 現在在日本以外的其他地方都是用這幾個字來稱呼 Perl &amp;amp; Raku 研討會了。但基本上 YAPC 跟 TPRC 這兩個名字指的都是由社群主辦的,主題包含 Perl 的研討會。 &lt;/p&gt;&lt;p&gt;雖然跑了不少地方的 Perl 研討會,但上次去到北美地區參與與 Perl 有點關係的研討會已經是 2004 年的 OSCON。芥於我還沒去踩過 &amp;quot;YAPC::NA&amp;quot; 這個領域,就想說就去看看吧。順便與那些社群舊友、網友、「GitHub PR 友」碰個面也好。 &lt;/p&gt;&lt;p&gt;TPRC 議程共有三日,議程共有三軌並行,儘量參加,但必定有三分之二是只能看錄影了。除了常規議程以外,與新舊朋友在午餐時間社交,也是這研討會的重點。讓我回想到以前的 YAPC::Taipei 與 OSDC 的那幾年了。先推薦幾場我有在座聽完的演講: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;The Test2 Ecosystem - Chad Granum. &lt;a href="https://youtu.be/7lNtM2FmTow"&gt;https://youtu.be/7lNtM2FmTow&lt;/a&gt; &lt;/li&gt;&lt;li&gt;Lingy &amp;amp; YAMLScript - News Ways to Program Perl - Ingy döt؜؜ Net. &lt;a href="https://youtu.be/9OcFh-HaCyI"&gt;https://youtu.be/9OcFh-HaCyI&lt;/a&gt; &lt;/li&gt;&lt;li&gt;&lt;a href="https://tprc2023.sched.com/event/1LhoB/the-n-queens-problem-by-regexp"&gt;The N-Queens problem by Regexp - Abigail.&lt;/a&gt; &lt;/li&gt;&lt;li&gt;&lt;a href="https://tprc2023.sched.com/event/1NIEZ/screwdriver-included-making-your-project-easier-to-enhance-and-extend"&gt;Screwdriver Included: Making your project easier to enhance and extend&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;演講主題形形色色,很容易就讓人聯想到多倫多市內 &lt;a href="https://en.wikipedia.org/wiki/Kensington_Market"&gt;Kensington Market&lt;/a&gt; 這區,裡面什麼樣的店都有。有滿足日間觀光客的小吃、咖啡店,也有讓當地居民能購物的生鮮市場,更有能滿足拍照欲望的街頭藝術。 &lt;/p&gt;&lt;p&gt; &lt;a data-flickr-embed="true" data-header="true" data-footer="true" href="https://www.flickr.com/photos/gugod/53071999920/in/dateposted/" title="The Car"&gt;&lt;img src="https://live.staticflickr.com/65535/53071999920_d78d4a0c36.jpg" width="376" height="500" alt="The Car"/&gt;&lt;/a&gt; &lt;br&gt; Kensington Market 內的地標。聽說常常換「新車」。&lt;/p&gt; &lt;p&gt;多倫多是個很大的都會區。雖然在此行之前從沒去過而讓人擔心,但從地圖上滿滿的公車站、地鐵站、路面電車,與密密麻麻的路線圖這一點看來,在市區內移動絕對不成問題。確實也是如此。一出 YYZ 機場,在售票機買了張 Presto 卡之後,就可以靠這張卡搭車移動。準備零錢也可以,但刷卡進出簡單多了。缺點是 6 CAD 的購卡費用與其中儲值金都不能退。考慮到以 Presto 乘車費用略為便宜一些,多乘幾趟就能把這 6 CAD 攤平,就決定買來用了。 &lt;/p&gt;&lt;p&gt;多倫多市內商業區都是超級高樓,之外則都是三層樓左右的矮房。拍街景時,很容易取到以巨大建築為背景的構圖。走在街上,有時會把遠方的高樓誤以為是山脈一般的錯覺。並且,無論怎麼走,都可以遇到大小工地,要不就是拆建房屋,要不就是修改馬路。工人們直接穿著作業服、戴著工地安全帽搭乘地鐵的姿態隨時隨處可見。多倫多市區是個正在經歷都市更新、新舊混合中的地方。 &lt;/p&gt;&lt;p&gt; &lt;a data-flickr-embed="true" data-header="true" data-footer="true" href="https://www.flickr.com/photos/gugod/53071512286/" title="聖彌額爾聖殿主教座堂"&gt;&lt;img src="https://live.staticflickr.com/65535/53071512286_0ba7269574.jpg" width="376" height="500" alt="聖彌額爾聖殿主教座堂"/&gt;&lt;/a&gt; &lt;br&gt; 聖彌額爾聖殿主教座堂。攝於 2023 年 7 月 13 日。與 &lt;a href="https://www.google.com/maps/@43.6545776,-79.377598,3a,75y,29.85h,115.55t/data=!3m8!1e1!3m6!1s1p_APRSt4tY99beqqvWqvA!2e0!5s20210901T000000!6shttps:%2F%2Fstreetviewpixels-pa.googleapis.com%2Fv1%2Fthumbnail%3Fpanoid%3D1p_APRSt4tY99beqqvWqvA%26cb_client%3Dmaps_sv.tactile.gps%26w%3D203%26h%3D100%26yaw%3D20.790518%26pitch%3D0%26thumbfov%3D100!7i16384!8i8192?entry=ttu"&gt;2021 年 9 月 Google 街景圖&lt;/a&gt;相比後,明顯可看到後方兩棟這三年蓋起來的。&lt;/p&gt; &lt;p&gt;Perl 程式語言,也正在經歷一段「都更」的過程。有很多新的機能出現之時,每項更新提案都會碰到現有居民的阻抗、競爭、妥協等等。就算是看來能帶來很美好的未來的提案,在有許多與現有生態相容議題要照顧的前提之下,未必都是能立刻成行的。有時就是得等到現有生態系消失了,阻力才會消退。雖然這也算是合情合理,但也造成了不少挫折。 &lt;/p&gt;&lt;p&gt;最近釋出的 perl 5.38 內所包含的 perl class,似乎相對來說是比較沒有阻礙的。畢竟,在物件導向概念風行了這麼久之後,大家對類別、物件等等的概念都有充分了解了,也就不會反對了。但即便如此,perl class 仍是個實驗性機能,一方面是因為幾位作者認為目前實做尚未完備,另一方面是因為大家已經習慣了將新機能以實驗性機能來推出的這個做法。 &lt;/p&gt;&lt;p&gt;無疑,Perl 社群是個很注重相容性的群體。 &lt;/p&gt;&lt;p&gt;儘管如此,仍有很多人在努力地替這老屋翻新。&lt;a href="https://www.youtube.com/watch?v=uT0S-jfO1mE&amp;amp;list=PLA9_Hq3zhoFwrDiojWd_lFUaOHlsUUEJa&amp;amp;index=10"&gt;Curtis 在他的主講&lt;/a&gt; 內提到了 &lt;a href="https://github.com/Perl-Oshun/oshun"&gt;Project Oshun&lt;/a&gt;、是繼 perl class 後以 Damian Conway 所設計的 &lt;a href="https://ovid.github.io/articles/language-design-consistency.html"&gt;KIM 語法&lt;/a&gt;去給變數與函數加上 data check (資料檢查、資料驗證)的機制。類似「型別」的概念。 &lt;/p&gt;&lt;p&gt;以下這段範例取自 Project Oshun。是以 &lt;code&gt;:returns&lt;/code&gt; 與 &lt;code&gt;:of&lt;/code&gt; 來標示出對函式與變數值的檢查規則。 &lt;/p&gt;&lt;pre&gt;&lt;code&gt;sub fibonacci :returns(UINT) ($nth :of(PositiveInt)) { ... }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;或許目前 perl 5.38 這語言就像是照片中前方的那聖彌額爾聖殿主教座堂,雖然顯舊,但在各方面都已經盡善盡美了。只是,如果不經歷一番改建,是無法再度像四周的高樓大廈那般,成為充滿新機會的場所。而要如何妥善地將這場所慢慢改築成更加便利、更有效率、更加親切的高科技教堂,則是目前 Perl 社群面對的議題了。 &lt;/p&gt;&lt;p&gt;&lt;a href="https://youtu.be/B2X_caTDcAI"&gt;Sawyer 在對 Perl 7 這個題目反省時&lt;/a&gt;,提到了他自認有溝通不足的狀況。溝通管道眾多,也不容易全數照顧到。對於&lt;a href="https://youtu.be/Q1H9yKf8BI0"&gt;他收到太多攻擊性言語而決意離開這事&lt;/a&gt;,我覺得太可惜,也太糟糕了。不過另一方面,我覺得他還是別再來這沱爛泥內攪和比較好。至少,每個人都應把自己的時間花在自認最值得的地方。 &lt;/p&gt;&lt;p&gt;顯然,網路言論環境的維護,是 Perl 社群更該努力處理的議題。不然,能在這個環境中存活下來的,就只是一些很會講髒話的人了。 &lt;/p&gt;&lt;p&gt;&lt;script async charset="utf-8" src="//embedr.flickr.com/assets/client-code.js"&gt;&lt;/script&gt; &lt;/p&gt;</content> <category term="tprc2023"/> <category term="tprc"/> <category term="yapc"/> <category term="perl"/> </entry> <entry> <id>https://gugod.org/2023/07/perl-5.38.0-released/?24502dec002e6b4c6a95b6559127448f0e0bde0c</id> <link rel="alternate" href="https://gugod.org/2023/07/perl-5.38.0-released/" type="text/html"/> <title>perl 5.38.0 釋出</title> <published>2023-07-03T11:47:37+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>perl-5.38.0 變更說明: <a href="https://metacpan.org/release/RJBS/perl-5.38.0/changes">https://metacpan.org/release/RJBS/perl-5.38.0/changes</a> </p> <p>摘要: </p> <ul> <li>內建的物件導向架構的改善:新增 <code>class</code>, <code>field</code>, <code>method</code> 三個定義類別的關鍵字。(實驗性機能。須以 <code>use feature 'class';</code> 打開。) </li> <li>新增對 Unicode 15.0 的支援。 </li> <li>新增:讓 <code>PERL_RAND_SEED</code> 環境變數為程式開跑時的亂數種子值。相當於去呼叫 <code>srand()</code> 。 </li> <li>讓語法錯誤訊息更加精簡。 </li> <li>自動在模組源碼 (內含 <code>package</code> 或 <code>class</code> 的 <code>.pm</code> 檔案) 最後補上 <code>true</code> </li> <li>內部用的函式的移除與其文件改善。 </li> <li>宣告廢棄:smartmatch (given / when)。名稱空間中的 <code>'</code> 分隔符號。 </li> </ul> <h2>內建的物件導向架構的改善 </h2> <p>這應該是這是兩三年來著力最多的部份吧。比起多數提供在 CPAN 上的 OO 框架,perlclass 相對來說很好懂。有三個新的關鍵字與其帶來的新語意,但是幾乎沒有新的語法規則,至少目前沒有。 </p> <p>參考:<a href="https://metacpan.org/release/RJBS/perl-5.38.0/view/pod/perlclass.pod">perlclass</a> 文件。 </p> <p>三個新關鍵字是:<code>class</code>、<code>method</code>、<code>field</code>。<code>class</code> 用來定義類別。<code>method</code> 用來定義 instance method,<code>field</code> 用來宣告 instance variable。 </p> <p>以 <code>class</code> 定義出來的類別會自動以 <code>new</code> 為其 constructor 函式,並且,所有 instance method 體內皆能以 <code>$self</code> 表示目前物件。class 體內的 instance method 的 signature 則不可包含 <code>$self</code>。 </p> <p>而 <code>class</code> 體內的 <code>sub</code> 可用來定義 class method, <code>class</code> 體內的 <code>my</code> 則可用來宣告 private class variable。 <code>class</code> 體內的 <code>our</code> 則可用來宣告 public class variable。 </p> <p>在同一 <code>class</code> 體內以 <code>my</code>、<code>our</code>、<code>field</code> 宣告出來的諸變數是共用同一個名稱空間的。名稱有衝突的話,只有最後一個變數會被留下。 </p> <p>在同一 <code>class</code> 體內以 <code>sub</code> 與 <code>method</code> 宣告出來的各函式也是共用同一個名稱空間的。名稱有衝突的話,只有最後一個函式會被留下。 </p> <p>以 <code>field</code> 宣告出來的變數為 instance variable,只能被用於 instance method 體內。 </p> <p>以 <code>method</code> 定義出來的函式為 instance method,體內可使用 instance variable,同時亦會自動有 <code>$self</code> 可用來代表目前物件。要呼叫其他同一 class 內的 class method 的寫法與普通函式呼叫相同。要呼叫 instance method 時則是需要對 <code>$self</code> 呼叫。 </p> <p>當做範例,以下是一個描述了五段變速電風扇的簡易類別。 </p> <pre> <code>use v5.38; use feature 'class'; use builtin 'true', 'false'; class Fan { use List::Util qw(min max); my $__id = 1; my $RPM_MAX = 600; my $RPM_MIN = 100; my $RPM_STEP = 100; sub vendor { "Cool Company" } sub speeds { ($RPM_MAX - $RPM_MIN ) / $RPM_STEP } field $id = $__id++; field $rpm = 3600; field $on = false; method id { $id } method speed { $rpm / $RPM_STEP } method turn_on { $on = true } method turn_off { $on = false } method faster { $rpm = min($rpm + $RPM_STEP, $RPM_MAX) } method slower { $rpm = max($rpm - $RPM_STEP, $RPM_MIN) } method TO_JSON { +{ # instance method / variable id =&gt; $self-&gt;id(), speed =&gt; $self-&gt;speed(), on =&gt; $on, # class method / variable vendor =&gt; vendor(), speeds =&gt; speeds(), rpm_max =&gt; $RPM_MAX, rpm_min =&gt; $RPM_MIN, } } }</code> </pre> <p>前述以 <code>sub</code> 定義出來的 class method,其實也可以被當成是 instance method 來呼叫。例如 <code>Fan</code> 類別的 <code>vendor</code> ,有兩種呼叫方式: </p> <pre> <code>my $fan = Fan-&gt;new; say $fan-&gt;vendor(); # (1) say Fan-&gt;vendor(); # (2)</code> </pre> <p>(1) 與 (2) 兩處對應到的函式是同一個。 </p> <p>以 <code>class</code> 所附的 <code>new</code> 函式所做出來物件,字串形式上會有個 OBJECT 字樣: </p> <pre> <code>my $fan = Fan-&gt;new; say "$fan"; #=&gt; Fan=OBJECT(0x19477b0);</code> </pre> <p>如果是以常見的 blessed HashRef 做法 (即:<code>bless {}, 'Fan'</code>) 所造出來的物件,其字串形式是這樣: </p> <pre> <code>Fan=HASH(0x1b3a5e8)</code> </pre> <p>由此可窺知在 perl 內部多了一種以 OBJECT 為表記的值。 </p> <h2>自動在模組源碼最後補上 <code>true</code> </h2> <p>以往都要在 <code>.pm</code> 檔案最後補個 <code>1;</code>,然後還得向人說明這行看似無作用的程式碼的用途。以後在開頭加上 <code>use v5.38;</code> 後就不必在檔尾補 <code>1</code> 了。 </p> <pre> <code># Foo.pm use v5.38; package Foo { sub foo() { "Bar" } }</code> </pre> <p>附帶一提,就算在最後在 Foo.pm 最後故意加上 <code>0;</code>,也不會讓 <code>use Foo;</code> 失敗。 </p> </div> </content> <category term="perl"/> </entry> <entry> <id>https://gugod.org/2023/06/perl-safe-navigation-monad-en/?d866ed7ac2b84e1caa64462866c4e52d40705156</id> <link rel="alternate" href="https://gugod.org/2023/06/perl-safe-navigation-monad-en/" type="text/html"/> <title>[Perl] Safe-navigation Monad.</title> <published>2023-06-18T17:02:02+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"><p>Recently on reddit.com/r/perl, pmz posted a question like this: </p><blockquote> <p>XML::Twig, get value (or not) without dying</p> <p>Currently I do:</p> <code><pre> if (defined $elt-&gt;first_child('addr')-&gt;first_child('postalCode')) { $patient{patient_postal_code} = $elt-&gt;first_child('addr')-&gt;first_child('postalCode')-&gt;text ; } </pre></code> <p>because if I don't check for "defined" and the resulting value is null , it dies.</p> </blockquote> <p>Link to the original post: <a href="https://www.reddit.com/r/perl/comments/1492sc1/xmltwig_get_value_or_not_without_dying/">https://www.reddit.com/r/perl/comments/1492sc1/xmltwig_get_value_or_not_without_dying/</a> </p><p>While on one hand the question is about how to use XML::Twig, on the other hand the obvious inconvenience here is when <code>first_child('addr')</code> returns <code>undef</code>, which means there are no <code>&lt;addr&gt;</code> element underneath, the following call of <code>first_child('postalCode')</code> would make the programm die. Generally speaking: in a chain of calls we expect objects to be present in all positions, but sometimes there are <code>undef</code>. Given that, is there a way to avoid the program from dying and let the entire call chain return <code>undef</code> if <code>undef</code> is encountered in the calling chain ? </p><p>To formalize the question a bit more generically: assume a class with instance methods <code>a()</code>, <code>b()</code>, and <code>c()</code>. These methods may return an instance of same class, or ocassionally, <code>undef</code>. Consider the following chain of calls originally from <code>$o</code>: </p><pre><code>$res = $o-&gt;a()-&gt;b()-&gt;c(); </code></pre><p>In case any of <code>a()</code>, <code>b()</code>, or <code>c()</code> returns <code>undef</code>, the program dies with messages like this: </p><pre><code>Can't call method "c" on an undefined value </code></pre><p>Which suggests <code>b()</code> returns <code>undef</code> and since <code>undef</code> is not an object, we cannot call methods on it. </p><p>Now, could we rewrite the same program to prevent the abovementioned error from happening, while making <code>$res</code> be <code>undef</code> if any of <code>a()</code>, <code>b()</code>, <code>c()</code> returns <code>undef</code>, or otherwise, the return value of <code>c()</code> ? </p><p>In some other programming languages, such purpose could be satisfied by using the safe-navigation operator, such as <code>?.</code> in javascript or kotlin: </p><pre><code>res = o.a()?.b()?.c(); </code></pre><p>Or in raku, <a href="https://docs.raku.org/language/operators#methodop_.%3F"><code>.?</code></a> </p><pre><code>$res = $o.a().?b().?c(); </code></pre><p>However, we haven't seen anything similar up until perl 5.38 just yet. </p><p>A rather intuitive way to rewrite would be something like this: </p><pre><code>$res_a = $o-&gt;a(); $res_b = $res_a &amp;&amp; $res_a-&gt;b(); $res = $res_b &amp;&amp; $res_b-&gt;c(); </code></pre><p>However, besides making the program much longer and less easier to grasp, the rewrite is not generic. It'll be different for similar statements with different method names. Not a good strategy. </p><p>Meanwhile, here's a super simple and generic way: </p><pre><code>$res = eval { $o-&gt;a()-&gt;b()-&gt;c() }; </code></pre><p>However, with the powerful side-effect of <code>eval</code>, all exceptions would be ignored while we are only interested in ignoring undefined values. That is a lot more than what we want. Even though it looks simple, it is probably not applicable. </p><p>Here is a solution with Monad design pattern. </p><p>The rewritten version looks like this: </p><pre><code>$res = SafeNav-&gt;wrap($o) -&gt;a()-&gt;b()-&gt;c() -&gt;unwrap(); </code></pre><p>The <code>SafeNav</code> is defined as the folowing. </p><pre><code>use v5.36; package SafeNav { sub wrap ($class, $o) { bless \$o, $class } sub unwrap ($self) { $$self } sub AUTOLOAD { our $AUTOLOAD; my $method = substr $AUTOLOAD, 2 + rindex($AUTOLOAD, '::'); my ($self, @args) = @_; # [a] (defined $$self) ? __PACKAGE__-&gt;wrap( $$self -&gt; $method(@args) ) : # [a.1] $self; # [a.2] } sub DESTROY {} };</code></pre><p><code>SafeNav</code> is a class that wraps all scalar values and equips with <code>AUTOLOAD</code> for responding to all method calls. </p><p>Inside <code>AUTOLOAD</code> there is the core part of our logic in [a]: If we are not wrapping an <code>undef</code> value, we call the original method on it, then re-wrap the return value ([a.1]). Or if we are wrapping an <code>undef</code>, we ignore the method call and just lay down and keep being ourselves ([a.2]). </p><p>Thanks to the mechanism of <code>AUTOLOAD</code>, the original form of <code>-&gt;a()-&gt;b()-&gt;c()</code> is kept exactly the same after the rewrite. Let's put both versions side-by-side for a quick comparison: </p><pre><code>$res = $o -&gt;a()-&gt;b()-&gt;c(); $res = SafeNav-&gt;wrap($o) -&gt;a()-&gt;b()-&gt;c() -&gt;unwrap(); </code></pre><p>The <code>wrap()</code> at the front, together with <code>unwrap()</code> at the back, form a clear boundary in which <code>SafeNav</code> is effective. Method calls after <code>unwrap()</code> are not not guarded by <code>SafeNav</code>. </p><p>With that, we properly ignore <code>undef</code> values, nothing more. If other kinds of exceptions are thrown from method a, b, c, the program would correctly abort. In the 3 proposed ways to rewrite the program in this article, the <code>SafeNav</code> monad is both generic and not adding too much verbosity to the original program. </p></div> </content> <category term="perl"/> <category term="monad"/> </entry> <entry> <id>https://gugod.org/2023/06/perl-safe-navigation-monad/?b4ba561110159ff157f8e7e5f45308a4428d6cd5</id> <link rel="alternate" href="https://gugod.org/2023/06/perl-safe-navigation-monad/" type="text/html"/> <title>[Perl] 以 Monad 來達成 safe navigation</title> <published>2023-06-18T17:02:02+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"><p>在 reddit.com/r/perl 板上看到 pmz 問了這樣子的一個問題: </p><blockquote> <p>XML::Twig, get value (or not) without dying</p> <p>Currently I do:</p> <code><pre> if (defined $elt-&gt;first_child('addr')-&gt;first_child('postalCode')) { $patient{patient_postal_code} = $elt-&gt;first_child('addr')-&gt;first_child('postalCode')-&gt;text ; } </pre></code> <p>because if I don't check for "defined" and the resulting value is null , it dies.</p> </blockquote> <p>原文連結: <a href="https://www.reddit.com/r/perl/comments/1492sc1/xmltwig_get_value_or_not_without_dying/">https://www.reddit.com/r/perl/comments/1492sc1/xmltwig_get_value_or_not_without_dying/</a> </p><p>這一方面是在針對 XML::Twig 模組的用法提問,另一方面是在問:當 <code>first_child('addr')</code> 傳回 <code>undef</code> 時,表示在目前 XML 文件樹中沒有 <code>addr</code> 元素,而後o方的連環呼叫 <code>first_child('postalCode')</code> 之處就會讓程式執行中斷,因為原本預期是物件的地方,也有可能是 <code>undef</code>。那有沒有能讓連環呼叫不會使程式失敗,並且在遇到 <code>undef</code> 時,讓整串算式的結果成為 <code>undef</code> 的辦法? </p><p>如果把題目重新描述得較抽象一些的話,就是:假設有一類別,其下有方法 <code>a()</code>、<code>b()</code>、<code>c()</code>。這三個方法可能會傳回 <code>undef</code> 或同一類別的物件。今有一物件 <code>$o</code> 屬此類別,考慮此連環呼叫式: </p><pre><code>$res = $o-&gt;a()-&gt;b()-&gt;c(); </code></pre><p>此式在 <code>a()</code> 或 <code>b()</code> 傳回 <code>undef</code> 時,就會讓程式中斷,並會出現像這樣的錯誤訊息: </p><pre><code>Can't call method "c" on an undefined value </code></pre><p>亦即:無法對 <code>undef</code> (undefined value) 呼叫 "c" 這個方法。這是當然的,因為 <code>undef</code> 並非物件。 </p><p>試問:有何手段能改寫此式,能避免前述錯誤之發生,使 <code>$res</code> 在 <code>a()</code>、<code>b()</code>、<code>c()</code> 任一者傳回 <code>undef</code> 時就算得 <code>undef</code>,且在全無 <code>undef</code> 情況下,又能正確算得 <code>c()</code> 的傳回值? </p><p>在一些語言中,這可輕易得透過使用 safe-navigation operator 或 optional chaining operator 來解決。例如 javascript 或 kotlin 中的 <code>?.</code>: </p><pre><code>res = o.a()?.b()?.c(); </code></pre><p>又例如 raku 語中的 <a href="https://docs.raku.org/language/operators#methodop_.%3F"><code>.?</code></a>: </p><pre><code>$res = $o.a().?b().?c(); </code></pre><p>但直到目前 perl 5.38 為止,在 perl 語言中尚未出現同等作用的算符。 </p><p>有個直觀的改寫方式是像這樣: </p><pre><code>$res_a = $o-&gt;a(); $res_b = $res_a &amp;&amp; $res_a-&gt;b(); $res = $res_b &amp;&amp; $res_b-&gt;c(); </code></pre><p>但在讓程式變長、用了多個臨時變數而讓程式碼變得稍微不好讀之外,這改寫法還不通用,碰到類似結構、名稱不同的式子就得手動從頭改寫。實在算不上是好辦法。 </p><p>此外,有個超間單的改寫方法: </p><pre><code>$res = eval { $o-&gt;a()-&gt;b()-&gt;c() }; </code></pre><p>但是,這個寫法的副作用,就是所有例外事件通通都會被忽略,雖然簡單好改,但其副作用很強。不見得在各種情境都適合。 </p><p>在此提供一個以 Monad Design Pattern 來達成得的一個解法。 </p><p>改寫方法如下: </p><pre><code>$res = SafeNav-&gt;wrap($o) -&gt;a()-&gt;b()-&gt;c() -&gt;unwrap(); </code></pre><p>其中 <code>SafeNav</code> 的定義為: </p><pre><code>use v5.36; package SafeNav { sub wrap ($class, $o) { bless \$o, $class } sub unwrap ($self) { $$self } sub AUTOLOAD { our $AUTOLOAD; my $method = substr $AUTOLOAD, 2 + rindex($AUTOLOAD, '::'); my ($self, @args) = @_; # [a] (defined $$self) ? __PACKAGE__-&gt;wrap( $$self -&gt; $method(@args) ) : # [a.1] $self; # [a.2] } sub DESTROY {} };</code></pre><p>這類別基本上是把所有純量值都包裝成物件。<code>SafeNav</code> 類別定義有 <code>AUTOLOAD</code> 這個特殊用途的函式,使其物件可接受所有方法呼叫。就算包著的值是 <code>undef</code> 方法呼叫也都不會失敗,而是會進入 <code>AUTOLOAD</code> 函式中。 </p><p>於是在 [a] 處就可進行核心處理:若自己包著的值不是 <code>undef</code>,就對其呼叫原方法([a.1] 處)。倘若自己包著的值已經是 <code>undef</code> 了,那繼續躺平做自己(?)就可以了([a.2] 處)。 </p><p>多虧有 <code>AUTOLOAD</code> 機制,原連環呼叫 <code>-&gt;a()-&gt;b()-&gt;c()</code> 的部份是原樣保留著的。在此並列、比較一下: </p><pre><code>$res = $o -&gt;a()-&gt;b()-&gt;c(); $res = SafeNav-&gt;wrap($o) -&gt;a()-&gt;b()-&gt;c() -&gt;unwrap(); </code></pre><p>前後的 <code>wrap()</code> 與 <code>unwrap()</code> 算是明確界定了 <code>SafeNav</code> 類別在此式中的作用範圍。過了 <code>unwrap()</code> 之後如果還繼續串著更多方法呼叫,就一定不是被包在 <code>SafeNav</code> 裡面的。 </p><p>這麼一來,會被「妥善忽略」的,就只有在碰到 <code>undef</code> 這個值的時候。若在 a、b、c 三個方法內發生了任何例外事件,程式還是能正確地被中止。並不會有太多副作用。在本文內提到的三種改寫辦法裡面,算是既通用,又不太囉唆的一種。 </p></div> </content> <category term="perl"/> <category term="monad"/> </entry> <entry> <id>https://gugod.org/2023/05/perl-cpan-toolchain-lyon-amendment/?c475b14fbd6acd54ad91e5877787666e210a1ce9</id> <link rel="alternate" href="https://gugod.org/2023/05/perl-cpan-toolchain-lyon-amendment/" type="text/html"/> <title>[Perl] Toolchain 方面對於 perl 版本的要求</title> <published>2023-05-06T14:33:09+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>最近開始看到 <a href="https://perltoolchainsummit.org/pts2023/">Perl Toolchain Summit</a> 的結果了。稍微讀了一下,以此篇文章綜合摘要一下今年在 Perl Toolchain 那裡的幾項決定(Lyon Amendment): </p> <ul> <li>原則上 toolchain 內的軟體 (註1) 會開始追上 (註2)「十年前」的 perl 版本。(註3) </li> <li>唯 2023 年例外,爲了提供給 RedHat v7 終活服務(?)而定爲 5.16。 </li> <li>明年 (2024) 定爲 5.20、後年 (2025) 定爲 5.22... (註4) </li> </ul> <p>如果有經常性在升級 perl 的話應該是不會因此受到甚麼影響。主要會被影響到的應該是一些因故無法升級的老系統,最糟有可能會變成不能使用 cpan 指令來安裝模組、或是有某些重要的模組在某版之後變成無法編譯、要使用的話就必須固定使用某個舊版。在老系統上安裝新模組的需求一般來說通常倒是安全性更新。考慮到作業系統本身也需要被更新,讓 Perl / CPAN 相關工具以類似作業系統更新的步調去「與時俱進」似乎還算是合理的。 </p> <p>註: </p> <ol> <li>主要是與 CPAN 生態系相關的各項工具與模組。包括模組的製作、測試、釋出、CPAN 伺服器端用的軟體等等。 </li> <li>原文用 "track" 這個字。這裡應該是指「如果在老於十年的 perl 環境內跑出錯誤也不再修理」的意思。 </li> <li>2013 年釋出的穩定版爲 5.18。 </li> <li>perl5 穩定版版號是每年往上加 2,並必定爲偶數。類似 Linux 的慣例。 </li> </ol> <p>參考: </p> <ol> <li><a href="https://rjbs.cloud/blog/2023/05/pts-2023-lyon-amendment-2-5/">PTS 2023: The Lyon Amendment (minimum perl) (2/5) by rjbs</a> </li> <li><a href="https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/lyon-amendment.md">lyon-amendment.md</a> </li> </ol> </div> </content> <category term="perl"/> <category term="cpan"/> <category term="toolchain"/> <category term="lyon"/> </entry> <entry> <id>https://gugod.org/2023/05/frogfind-search-engine/?5d92450644daaa473ac1e1c13cbd241f3d4c2f1c</id> <link rel="alternate" href="https://gugod.org/2023/05/frogfind-search-engine/" type="text/html"/> <title>frogfind 搜尋引擎</title> <published>2023-05-03T09:21:51+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p><a href="http://frogfind.com/">http://frogfind.com/</a> </p> <p>(注意: http 網址。其實用 https 也可以連,但是站長沒有把 cert domain 弄對。看來是同一台機器上架了多個網站,然後就「順便」多了一個錯誤的 https 進入點。) </p> <p>一陣子之前在 HN 上紅了一陣子的這個網站是個搜尋引擎兼 web proxy。作者要在爲了要讓他蒐集的三十年前的老電腦也可以看各網頁而做了這個特殊的 web proxy。 </p> <p>實際上看來是把搜尋丟去 duckduckgo,並且把搜尋結果中的每個網址都換成他的 read.php,而 read.php 中實做 Readability 演算法,把原網頁中能內容極度精簡化再送回給 browser。 也因此有可能會碰到無法處理的網頁。但,在 Readability 演算法管用時的瀏覽體驗非常的好。 </p> <p>因此,給記憶體比較不足的機器(如 Raspberry Pi)來配合 w3m / lynx / eww 等<a href="https://gugod.org/2020/05/text-only/">純文字</a>瀏覽器來用也是非常合的。 </p> <p>源碼: <a href="https://github.com/ActionRetro/FrogFind">https://github.com/ActionRetro/FrogFind</a> </p> </div> </content> <category term="search"/> <category term="proxy"/> </entry> <entry> <id>https://gugod.org/2023/04/perl-cpan-install-dbd-mysql-with-miariadb-config/?43ad1427f9493d6e3fe635fd83e80cc9c5eb3500</id> <link rel="alternate" href="https://gugod.org/2023/04/perl-cpan-install-dbd-mysql-with-miariadb-config/" type="text/html"/> <title>[CPAN] 如何在安裝 DBD::mysql 時使其使用 MariaDB 的編譯設定</title> <published>2023-04-29T09:22:06+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>簡單筆記一下。以 Debian 爲例。 </p> <p>在安裝 <code>DBD::mysql</code> 時需要 <code>mysql_config</code> 這個指令,但如果要使用 MariaDB Client 而不能安裝 MySQL Client 時,也可以讓 <code>DBD::mysql</code> 去使用 <code>mariadb_config</code>,使其改與 libmariadb 連結。由於 MariaDB Client 也可以用來與 MySQL Server 溝通,在不想額外加入 mysql 套件的時候也可以使用這招來省點事。 </p> <p>首先需要裝好開發與編譯用的函式庫: </p> <pre> <code>sudo apt-get install libmariadb-dev </code> </pre> <p>然後是在安裝 <code>DBD::mysql</code> 時,透過指定環境變數的方式,讓其在編譯過程去使用 MariaDB 的編譯設定: </p> <p>以 cpm 指令來裝 </p> <pre> <code>DBD_MYSQL_CONFIG=/usr/bin/mariadb_config cpm install -g DBD::mysql </code> </pre> <p>以 cpanm 指令來裝 </p> <pre> <code>DBD_MYSQL_CONFIG=/usr/bin/mariadb_config cpanm DBD::mysql </code> </pre> <p>以 cpan 指令來裝 </p> <pre> <code>DBD_MYSQL_CONFIG=/usr/bin/mariadb_config cpan -i DBD::mysql </code> </pre> <p>以上。 </p> </div> </content> <category term="perl"/> <category term="cpan"/> <category term="DBD::mysql"/> <category term="MariaDB"/> </entry> <entry> <id>https://gugod.org/2023/03/yapcjapan-2023-and-kyoto-short-trip/?b9e3c7fc21830786aad81ec165d0541095b52ca0</id> <link rel="alternate" href="https://gugod.org/2023/03/yapcjapan-2023-and-kyoto-short-trip/" type="text/html"/> <title>YAPC::Kyoto 2023 的參與,以及京都短行</title> <published>2023-03-23T08:07:00+09:00</published> <author> <name>gugod</name> </author> <content type="html" xml:base="https://gugod.org">&lt;p&gt;這次 &lt;a href="https://yapcjapan.org/2023kyoto/"&gt;YAPC::Kyoto 2023&lt;/a&gt; 的實體聚會應該是 Perl 社群最想參加的一次聚會了。原本預計是在 2020 年三月舉辦的,但因為當時 COVID-19 傳染狀況的關係不得不取 消。就算沒有取消,大概實際上也不會有人要去。而就過了這麼三年,所有研討 會不得不降級為只有線上舉辦,讓大家透過群組視訊會議與線上文字聊天室來模 擬實體聚會。 &lt;/p&gt;&lt;p&gt;主催者 papix 一直把此事定調為延期,而不是取消。除了個人堅持之外,原來也與其公司(&lt;a href="https://hatena.co.jp/"&gt;はてな&lt;/a&gt;)是在&lt;a href="https://www.krp.co.jp/"&gt;京都リサーチパーク&lt;/a&gt;(京都研究園區)創業這一點有直接的關聯。這點倒是在聽完了最後的主講之後才明瞭的。 &lt;/p&gt;&lt;p&gt;京都研究園區是此次研討會場地的所在。這園區內共有十五棟大樓,有辦公用也有活動用。其地點離京都水族館不遠,但是是一個觀光客不太會停留的地區。園區內有辦活動專用的場地,雖然並不像中研院那麼大規模,但教室大小適中,動線容易理解,也有很大間的,適合全員聚集的地方。 &lt;/p&gt;&lt;p&gt;我稍微早到了一些而目睹了工作人員仍在準備的狀況,因此先在場地附近隨意散步了一下。再回報到處時不小心從舞台後面走出來了。正好碰到 papix 在佈置 Perl 神社而搭了幾句話。 &lt;/p&gt;&lt;p&gt;&lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/52769535255/in/datetaken/" title="Perl 神社與鳥居"&gt;&lt;img src="https://live.staticflickr.com/65535/52769535255_68a9364436_c.jpg" width="602" height="800" alt="Perl 神社與鳥居"/&gt;&lt;/a&gt;&lt;&lt;/p&gt; &lt;p&gt;這神社就是一個鳥居、一個小賽錢箱、跟御神體:一本日文版《Perl 學習手冊》。賽錢箱所募得的款,會被捐給 Perl 基金會。 &lt;/p&gt;&lt;p&gt;哦,去年是讓 perlbrew 成為酒標,今年是要讓 Perl 成為宗教了嗎。我當下這突然這麼想。元是技術、先是商品化、再是宗教化。很會哦。不過,這三件事其實也不一定是那麼壁壘分明的。 &lt;/p&gt;&lt;p&gt;Perl 本體的宗教感一直都是存在著的。像是 Perl5 內製造物件的關鍵字是為 &lt;code&gt;bless&lt;/code&gt; 而不是 &lt;code&gt;new&lt;/code&gt; 的這一點,就使其獨一無二。&lt;code&gt;bless&lt;/code&gt; 語意是「祝福」,若要讓宗教感強一些的話或許可用「加護」來表意。(雖然這邊把佛教用語用在天主教情境下了,但請讓我在此模糊一點。) &lt;/p&gt;&lt;pre&gt;&lt;code&gt;my $it = { &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;Learning Perl&amp;quot; }; my $obj = bless $it, 'Book';&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;普通變數在接受加護過後,就會成爲物件。 &lt;/p&gt;&lt;p&gt;這大概就是 Perl 本體內宗教感的來源了。 &lt;/p&gt;&lt;p&gt;不過大部分 OO framework 模組為了迎合流行,又各自將建立物件的方法名稱定為 &lt;code&gt;new&lt;/code&gt;,日常寫程式時倒是沒有一直在施法加護的心情。 &lt;/p&gt;&lt;p&gt;這次倒沒有甚麼人再度發表新的 OO Framework,不過值得一提的是 perl 5.37 已經開始內建 &lt;code&gt;class&lt;/code&gt; 關鍵字,可用來定義類別與物件。並且絕贊更新中。可能會有一些人覺得 perl5 的物件導向支援太原始、而這 &lt;code&gt;class&lt;/code&gt; 關鍵字來得太遲了。但是在很多時候,遲到總比沒到好(Better late than never.),或許這就是那種時候。在物件導向系統完善了之後,或許接下來可以期待型別系統、多重分派等等更有利與效能的子系統出現在 Perl 中了。這麼一來或許 Perl 又會與 Raku 稍微接近了一些。 &lt;/p&gt;&lt;p&gt;在報到處領到研討會手提袋跟一整袋贈品後稍微看了一下,發現這次的幾年 T 恤設計很簡單明瞭。正面「you bless it」一句話。圈外的人大概會覺得這顯然是件意義不明的怪 T 恤。但社群內的人就能知道 bless 這個的特殊意義而在臉上露出會心一笑。 &lt;/p&gt;&lt;p&gt;如果在程式碼內到處都是 &lt;code&gt;bless&lt;/code&gt; 會不會讓人有在施法的感覺這我是不太知道了,不過另外一點會讓 Perl 程式變得好像在施法的就是內建在語言中的正規表示式引擎了。 &lt;/p&gt;&lt;p&gt;例如 dankogai 這次發表的演講標題爲: &lt;/p&gt;&lt;pre&gt;&lt;code&gt;my$talk=qr{\b((?:ir)?reg(?:ular )?exp(?:ressions?)?)\b}ig; &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;據本人說,他也不知道要怎麼把這個標題用嘴巴說出來。 &lt;/p&gt;&lt;p&gt;確實,在程式內有很多正規表示式的時候,程式碼會變得很難唸,而對於像我這種依賴聲音來記憶的人來說,唸不出來的文字就比較不好記。或許哪天開始我該擅自把正規表示式內內各記號對應到口腔內各發聲部位,賦予其音素,然後試着唱出來。說不定會很有趣。 &lt;/p&gt;&lt;p&gt;與 Perl 神社稍微有點距離的贊助廠商攤位區內可以抽運勢籤,由面白法人這個長期贊助商提供。我當日的運勢是小吉。其中關於「移管」的部分的內容是 &lt;code&gt;undef&lt;/code&gt;。這真是有趣。 &lt;/p&gt;&lt;p&gt; &lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/52769375024/in/datetaken/" title="今日運勢:小吉"&gt;&lt;img src="https://live.staticflickr.com/65535/52769375024_f61ce671cf_c.jpg" width="602" height="800" alt="今日運勢:小吉"/&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;字面上 &lt;code&gt;undef&lt;/code&gt; 是表示無值,但在搜尋系的 API 中有時侯會被拿來當作是「沒有、隨便、都可以」這幾種意義。在更新 (PUT / PATCH)系的 API 內又可代表要將部分內容刪除的意義。與 0、1 一樣,是十分有用的一個關鍵字。但這籤怎麼解? &lt;/p&gt;&lt;p&gt;Perl 神社內沒有神職人員可以問,但如果是我自己擅自解釋的話,我會說:Whatever | Mu。 &lt;/p&gt;&lt;p&gt;當天在 Twitter 上看到有人抽到了運勢全是 undef 的籤。完全是超越大吉的籤種,真是令人羨慕。 &lt;/p&gt;&lt;p&gt;於主會場找個好位置坐下後,立刻就碰到了 charsbar 與 skaji,也將 dankogai 的演講完整聽完了。中午過後又碰到了 miyagawa。常見的狠角色通通都到了。稍微問候幾句之後,也立刻讓人覺得:現在能這樣面對面的 跟這些人簡單講幾句話,還真是難得啊。 &lt;/p&gt;&lt;p&gt;看時刻表發現午餐時段內有堂奇妙的課可以聽,領了便當進去教室坐下後發現講臺上是幾位&lt;a href="https://podcasters.spotify.com/pod/show/notainc/episodes/10-CIVICTO-e1ncelb/a-a8fpfu0"&gt;今出川.FM 在做 Podcast 節目&lt;/a&gt;的人在錄音。在座位上吃便當的同時可以用聽廣播節目的心情來邊聽邊吃,同時還可以透過 slido 發問題給他們回答。這真是有趣的一段經驗。可以給還有在辦研討會跟還有在做 Podcast 節目的人參考參考。 &lt;/p&gt;&lt;p&gt; &lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/52768581597/in/datetaken/" title="午餐節目收錄中"&gt;&lt;img src="https://live.staticflickr.com/65535/52768581597_7657cd3d0f_c.jpg" width="800" height="602" alt="午餐節目收錄中"/&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;除了去參加研討會,這次也趁著有春分之日請了連假在京都觀光了幾天。但也沒有安排行程細節,只有幾件想做的事。如果天氣好就外出,如果天氣不好就再找看看有沒有好備案。很幸運的,天氣基本上還不錯。先花了一個早上去稻荷山上走了一整圈,就是千本鳥居的那座山。當然,那裡是個人氣旺盛的觀光地區,觀光客人數真是多。鳥居底下人多的狀況就像站滿人的電扶梯。大家都只能慢慢地往前方移動,沒有辦法在半途離開。當然,越往山上走,人就越少。 &lt;/p&gt;&lt;p&gt; &lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/52769374799/in/datetaken/" title="千本鳥居A面"&gt;&lt;img src="https://live.staticflickr.com/65535/52769374799_51f281260a_c.jpg" width="602" height="800" alt="千本鳥居A面"/&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;走上稻荷山山頂並不是太困難的。雖然有十分多樓梯階段,但基本上走走停停也一下子就到了。山頂附近有三群神社叢集,或者應該說整座稻荷山上其實大大小小有十來群神社叢集。要全部仔細看完的話還真的是要不少時間。在山頂區發現了這樣的一個看板: &lt;/p&gt;&lt;p&gt; &lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/52772056901/in/dateposted/" title="山頂:不要再問了"&gt;&lt;img src="https://live.staticflickr.com/65535/52772056901_33e3d43c3e_c.jpg" width="602" height="800" alt="山頂:不要再問了"/&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;顯然是在有太多人會跑去問神社旁邊的小賣店「這裡就是山頂了吧?」這種基本問題而讓店家不勝其煩。只好明確設下阻擋規則:問其他問題可以,問這個問題不行。 &lt;/p&gt;&lt;p&gt;由 &lt;a href="https://twitter.com/kazeburo"&gt;kazeburo&lt;/a&gt; 所分享的〈DNS権威サービスへのDDoSとハイパフォーマンスなベンチマーカ〉是關於 DNS random subdomain attack -- 基本上就是如果有很多人來查詢 &lt;code&gt;xx1.example.com&lt;/code&gt;, &lt;code&gt;xx2.example.com&lt;/code&gt;, &lt;code&gt;xx3.example.com&lt;/code&gt;... 等以一大堆隨機生成的名稱,那麼 DNS 伺服器要不就是會因爲頻寬被這些噪音佔去而讓服務品質降低,要不就是會因爲軟體內的熱騰騰的快取內容被一堆路人甲乙丙丁擠走了而變是快取失準。真的要遇到這種類型攻擊時,如果祭出類似「來問 &lt;code&gt;*.example.com&lt;/code&gt; 的一律當作沒看到」這種太廣泛的阻擋規則的話,又相當於是自己把自己的服務給廢了。因此不是很容易處理。似乎就是得讓改寫 DNS 伺服器軟體本身的演算法,讓「查無此處」變成是最快的途徑。 &lt;/p&gt;&lt;p&gt;上稻荷山山頂前的四達路口顯然是聚集了最多人的地方。所有還想往上走的人都必定會經過那裡、或許休息一下。所有已經不想再往上走的人也必定會在那裡休息到體力回復了為止。當天早上在耳邊通過最多的語言是西班牙語。厲害啊,西班牙語。 &lt;/p&gt;&lt;p&gt;這幾年的 yapcjapan 研討會的議程幾乎全是日語的,幾乎沒有任何以非日語發表的議程。不過這次有位遠道而來的講者 nugged 他主要是來替八月份辦在赫爾辛基的 &lt;a href="https://perlkohacon.fi/"&gt;YAPC::Eurpoe -- Perl + Koha Conference&lt;/a&gt; 宣傳的。據他所言,Koha 是一套廣爲使用的圖書館管理系統,而這次研討會將會辦在圖書館內。看來這顯然會是一次非常獨特的、能讓人旅行兼充電的研討會。 &lt;/p&gt;&lt;p&gt;河原町與四条一帶也是一個很容易讓人充電的地方。那一帶能讓客人充電的連鎖咖啡店很多,各種大小商店也很多、很好逛。最近 幾次到京都都會在 Holly's Cafe 充電。這次也是利用了這間連鎖店提供的電源服務。其實這連鎖店的飲食方面沒有甚麼太特殊的地方,不好不壞,只是通常其分店內都設有爲數不少的電源插座,店面本身不小。對於有此需要的客人來說 資源充足,比較不會讓人去了纔發現因客滿而沒有插座可用。也就是說這連鎖店的電源服務的可用性程度很高(High Availabality)。 &lt;/p&gt;&lt;p&gt;而說起來像神社這種場所的可用性程度也算是很高了。對於幾類到場「客戶」 (參拜者),只要將神社境內幾項伺服器維護妥當便可讓參拜者自行服務,例如: 鳥居與參道、淨手、抽運勢籤、托願於繪馬、參拜(許願)、賽錢。基本上只要各項硬體設施沒有損壞,就可以 同時滿足大量客戶來訪,是可用性程度很高的。 &lt;/p&gt;&lt;p&gt;只是也有例如:求御守、求御朱印、問事、求加護。這類服務內容需要神職人員來真人服務,無法輕易地規模化,可用性的程度也就受到服務者人數限制。而就算是無需人類提供服務的伺服器,在來客數很多時,也是無法同時滿足所有客人的要求。參拜者必須當場自行協調、等候。也就是在來客數多時,必會有排隊情況發生。 &lt;/p&gt;&lt;p&gt;在神社系統內要解決排隊問題,就是要把空地騰出來,提供座位區讓人坐着等。或許這就是爲何各設施之間不會離得太近的原因。又或者,若像淺草神社那般人氣旺盛者,偶爾得把筆直的參道全部分配給排隊人潮來用。 &lt;/p&gt;&lt;p&gt;而軟體系統內排隊除了要有空地(臨時的儲存空間)之外,還必須要有某些機制來確保隊伍整體有在向前行進,隊伍最前端的客戶能立刻被處理、處理次序先後必須依照特定規則等等。無論隊伍內容是連線、網址、背景工作。都是類似的問題。 &lt;/p&gt;&lt;p&gt;這次正好聽到 GMO 公司的 SRE 在分享他們把工作佇列(Job Queue) 改爲 fireworq 的事情。他們一直在使用 TheSchwartz,卻感到諸多不便處而改用 fireworq。兩者分派工作的模式不同,各有優缺點。但看來 fireworq 有個獨特的優點是它本身是個 HTTP JSON API 形式的伺服器,只是負責處理排隊事宜(或者說:讓人抽號碼牌、叫號),不處理實際工作內容。因此它能夠配合任何既有系統內來使用,所有程式語言皆可。實際上負責工作的函式則必須要能以 HTTP JSON API 的形式來接受工作之外,最好亦必須爲冪等實做(Idempotent by implementation),也就是說:同樣的工作重複多次進行也不應對系統造成任何衝擊。 &lt;/p&gt;&lt;p&gt;初步聽起來,如果有將系統一部分從 A 語言改寫成 B 語言的需求的話,或許也可以透過 fireworq 的使用,讓轉移稍微容易一些。又或者是在資源調配方面,由於實際上進行工作的伺服器也是 HTTP 伺服器,對於已經有維護 HTTP 伺服器的人員而言,所有調配資源的慣例或操作步驟皆可通用。 &lt;/p&gt;&lt;p&gt;這麼說來 Holly's Cafe 等咖啡連鎖店需要人員的服務就是最開始的點餐與結帳。事實上幾乎所有連鎖咖啡店都是讓客人一開始就把點餐、結帳兩個步驟完成。一間店多半設置了兩個點餐臺可以做負載平衡,在服務人員配置比較少的店面則是連取餐都同步完成了。所有服務作業都是在前景(客人面前)完成。雖然要讓客人等一下,但既然在人力工作資源有限時無法分配任何人去做背景作業,也就是讓客人先拿個號碼牌走而幾分鐘後再由店員將商品送上,那讓所有要求同步完成,亦不失爲一個好辦法。 &lt;/p&gt;&lt;p&gt;稻荷山上的千本鳥居其實一座一座上都刻寫了神社贊助者的大名。看來是一般公司行號(或個人)在捐了款之後便能立座掛名的鳥居。從山頂上下來時,可看到玲琅滿目的贊助商大名以及起立年份。有點令人意外的是,其實大部分的鳥居都頂新的,最近十年內年左右立起來的似乎佔了大多數。超過十年以上的就不太常見了。不過我所注意到最老的一座是大正五年(1916)的,而且看來是混凝土之類的材質,不是木造的。不知還有沒有更早的。 &lt;/p&gt;&lt;p&gt; &lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/52769607463/in/datetaken/" title="千本鳥居B面"&gt;&lt;img src="https://live.staticflickr.com/65535/52769607463_7f383b41a9_c.jpg" width="602" height="800" alt="千本鳥居B面"/&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;一般在稍有規模的神社建地內,除了各種服務參拜者的硬體設備之外,也有類似的工商服務設備,基本上都是各種形式的捐款者名錄。雖然不一定會像千本鳥居這麼遠近馳名,例如文字看板、燈籠陣列等等。雖然大小醒目程度不同,但都是要將捐款者大名清清楚楚地顯示出來給參拜者看而設置的硬體。這類掛名讓人看的做法似乎由來已久,替神社這種宗教感滿點的場所混入了一些些商業氣息。亦如教堂與市集、廟口與夜市,在宗教設施附近,商業與宗教兩者總是處於一種互相廣告、互相依賴的關係。既然一直有人會到神社來參拜,那神社就是一個能夠提升知名度的地方。是不是有點像「入口網站」呢? &lt;/p&gt;&lt;p&gt; &lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/52760762042/in/datetaken/" title="贊助商"&gt;&lt;img src="https://live.staticflickr.com/65535/52760762042_5343e9bd7d_c.jpg" width="800" height="390" alt="贊助商"/&gt;&lt;/a&gt; &lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/52769374239" title="電電宮會員名錄"&gt;&lt;img src="https://live.staticflickr.com/65535/52769374239_f8e6e497dc_c.jpg" width="800" height="602" alt="電電宮會員名錄"/&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;正如同神社參拜者在登堂參拜之前就會看到各種形式的贊助者列表,YAPC 與會者們在進入場地的同時也會開始接觸到贊助商的大名。日本這裡辦的 YAPC 研討會,是自一開始就十分重視贊助商的曝光度的。贊助商除了能在走廊擺攤,其大名會出現在網站上、在於報告出領到的手提袋內、在講臺後方的背景看板上、在大講堂螢幕兩邊掛着的布條上、在議程表上、以及各教室的名稱、還會被主辦者在謝幕之前口頭逐一點名致謝。有這麼多時機能讓讓贊助商大名曝光。而所有與會者,既是「消費者」(使用 Perl / CPAN 的人),也是「經營者」(製造 CPAN 模組、開源專案、貢獻給 Perl 生態系的人);藉由參與研討會,還是「Perl 宗教感」的起立者、贊助者。在這層表現上,年年在世界各地舉辦 YAPC 似乎就像是種「Pop-up 神社」之類的,讓人來大拜拜的地方。而這次研討會 T 恤上的「you bless it」這句話似乎正好替這種種宗教活動感給總結了。或許這種像是魚幫水、水幫魚的方式,就是一種能使其規模向上提升、讓系統容量更大的方式。 &lt;/p&gt;&lt;p&gt;&lt;a href="https://www.gmo.jp/"&gt;GMO&lt;/a&gt; 公司 SRE &lt;a href="https://twitter.com/rsym1290"&gt;@rsym1290&lt;/a&gt; 所發表的〈 4PB(ペタバイト)を超えるオブジェクトストレージをハードウェアからアプリケーションにかけて運用するノウハウ 〉,是關於他們製作的 Bayt,這是在 API 層相容於 S3、底層爲 MogileFS、目前容量約爲 4PB 網路儲存伺服器。這項服務是提供給 GMO 公司內部各專案使用的,也因此有此規模,實際上在費用使用彈性方面也比 AWS S3 更好一些。也提到最近版半導體短缺的狀況,實際上也影響到了他們日常硬碟淘汰換新作業。普通約兩個月可以到貨的新硬碟,變成要等六到十二個月這種極爲不安定的日期。 &lt;/p&gt;&lt;p&gt;在 YAPC::Asia 2007 時,&lt;a href="https://bradfitz.com/"&gt;Brad Fitzpatrick&lt;/a&gt; 曾經分享過讓 LiveJournal 系統能規模化的建構方式(主要是談 mysql)。當時他也提到,爲了將系統規模化,他做了 &lt;a href="http://gearman.org/"&gt;Gearman&lt;/a&gt; (分散式工作排程)、&lt;a href="https://github.com/mogilefs"&gt;MogileFS&lt;/a&gt; (網路儲存系統)、memcached (網路快取服務)、以及當時才剛開始做的 &lt;a href="https://metacpan.org/pod/TheSchwartz"&gt;TheSchwartz&lt;/a&gt; (工作佇列)。Gearman 這名字是取自於 &amp;quot;Manager&amp;quot; 這個單字的易位構詞(anagram),而 MogileFS 這名字則是取自於 &amp;quot;OMG Files&amp;quot; 的易位構詞。不過,他當初沒有提到 &amp;quot;TheSchwartz&amp;quot; 和 &amp;quot;memcached&amp;quot; 是甚麼其他詞彙的易位構詞(笑)。 &lt;/p&gt;&lt;p&gt;隨着系統的規模化,部件與模組越添越多,能故障的地方也就會越來越多。如果平時都系統架構沒有一定的熟悉度,也未必對應得來。雖然有不少問題可以藉由退到舊版來解決,但也有很多狀況是與新版的釋出並無直接相關,而是在架構中有什麼地方壞了。什麼地方容量不夠了。若是不知道架構中有哪些模組、彼此之間是如何相連、那顯然就沒辦法仔細找出問題的根源。只能夠暫時迂迴、避開會讓問題發生的路徑。好比這間點餐機壞掉的麵店: &lt;/p&gt;&lt;p&gt; &lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/52769606633/in/datetaken/" title="某件麵店門口與其故障中的點餐機"&gt;&lt;img src="https://live.staticflickr.com/65535/52769606633_1084ec63a5_c.jpg" width="800" height="602" alt="某件麵店門口與其故障中的點餐機"/&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;店內的店員、廚師、店長都沒有人知道該如何修理那台故障的機器,但店員仍然能用老方法以口頭接待、把訂單記在紙上、以訂單出餐、按計算機計算總額之類的。來順利完成經營麵店所該做的工作流程。 &lt;/p&gt;&lt;p&gt;有幾位講者分享了與錯誤處理、故障對應相關的主題。分別是&lt;a href="https://twitter.com/ryuichi_1208"&gt;ryuichi_1208&lt;/a&gt; 的〈入門障害対応 「サービス運用はTry::Catchの繰り返しだよ、ワトソン君」〉、以及&lt;a href="https://github.com/sadnessOjisan"&gt;sadnessOjisan&lt;/a&gt; 的〈my new error...〉。都是能讓我有所借鏡的主題。特別是關於故障對應的部分。講者提到平時的「演習」很重要,這部分特被有有同感。各個專案都應該在故障對應是順便做一份實戰手冊,讓未來的組員們能夠依照手冊內容來快速判斷那些時候該做什麼操作。同時也可以依照手冊來做練習。平常開發是得程式碼中四處加入妥善的錯誤處理與記錄,隨時翻翻記錄也能有助於在有大規模故障是能快速動作。 一件一件都是需要練習的事情。總不能只因爲點餐機秀逗,就讓客人喫不到麵吧? &lt;/p&gt;&lt;p&gt;&lt;a href="https://corp.helpfeel.com/"&gt;Helpfeel&lt;/a&gt; 公司的 &lt;a href="https://nibo.sh/"&gt;niboshi&lt;/a&gt; 所分享的〈&amp;quot;普通&amp;quot;のWebアプリでWASMを活用する〉似乎值得參考。主要大意爲他們有許多文字資料需要同時在伺服器段與網頁段解析,爲了避免維護兩套不同語言版本解析器而試著選用 WASM 看看。目前階段是使用 Rust 實做解析器,並編爲 .wasm 讓 python 與瀏覽器 javascript 來使用。 &lt;/p&gt;&lt;p&gt;雖然是一段還在摸索的過程,但這種實例正好符合 WASM 的強處。似乎值得探索看看。 &lt;/p&gt;&lt;p&gt;在研討會開幕時,螢幕上播放了一段影片。內容是兩位主辦者在法輪寺內求加護,神職人員(*)以特有聲調唸著像是經文的一段話,但仔細一聽是「願 YAPC 舉辦順利」之類的內容,而加護對象是一本書。也就是放在 Perl 神社內的那本《Perl 學習手冊》。這本書在閉幕時,以「學生應援」的名義,贈送給了某位學生。賽錢箱最後募得了一萬四千餘元,而御神體竟然是做爲贈品送出去了,這真是一段不錯的始末。 &lt;/p&gt;&lt;p&gt;(*): 我無法從服裝判斷唸經者的職階,只好用這種通用名詞來代稱了。 &lt;/p&gt;&lt;p&gt;在旅行最後一日,我也到了法輪寺去簡單參拜一下,我參拜的對象是寺內的電電宮。並且求得了「電電宮御守」與「情報守護」(貼紙)兩項物品。願:半導體能自短缺狀態逐漸恢復,人人有硬碟跟 GPU 可買,bcrypt 回數節節高昇,密文密得不得了。 &lt;/p&gt;&lt;p&gt; &lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/52769534260/in/datetaken/" title="法輪寺"&gt;&lt;img src="https://live.staticflickr.com/65535/52769534260_07d93da910_c.jpg" width="800" height="602" alt="法輪寺"/&gt;&lt;/a&gt; &lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/52769534330/in/datetaken/" title="電電宮"&gt;&lt;img src="https://live.staticflickr.com/65535/52769534330_b07cc6209a_c.jpg" width="602" height="800" alt="電電宮"/&gt;&lt;/a&gt; &lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/gugod/52769534080/in/datetaken/" title="電電宮御守、情報安全護符"&gt;&lt;img src="https://live.staticflickr.com/65535/52769534080_37207af19d_c.jpg" width="800" height="602" alt="電電宮御守、情報安全護符"/&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;依照這次場地地點,我選擇了一間位於下京區靠中京區的飯店。下京區與中京區這一帶有很多小巷可以探索,三条商店街也是個好逛的地方。雖然附近就有世界遺產二条城,但寧靜的巷內街景在我眼裡也是一樣出色。這一區的房子尚比較矮小,也還沒有被改建爲大規模的高樓。但從偶爾出現的工地來看,或許接下來也會面臨都市更新吧,屆時風景必然會有顯著改變,趁現在多多拍些照片吧。 &lt;/p&gt;&lt;p&gt;在春分之日早上,我還是到二条城內去看看庭園、看看御殿。這市區內的世界遺產果然是值得一看。中午時偶然碰到「&lt;a href="https://www.city.kyoto.lg.jp/bunshi/page/0000264257.html"&gt;さくらパレード&lt;/a&gt;」這個由關西各校吹奏樂部聯合參加的遊行活動。事前並不知道,是碰巧路過京都市役所時聽到樂聲、調查了一下纔知道是個年年有辦的活動,但過去幾年因 COVID-19 流行而中止。 &lt;/p&gt;&lt;p&gt;也正好因爲我完全沒有任何行程與計劃,看到這個遊行活動,就當下決定依照其時間來看遊行。橘高校是遊行的壓軸,但其他如島根県立出雲商業高等学校、兵庫県滝川第二高等学校、都是實力不相上下的。整段遊行看下來很過癮,也感受到了人情與活力。雖然是碰巧,但沒有預約任何行程而可以隨意即使調整,真是太好了。 &lt;/p&gt;&lt;p&gt;無巧不書。這次的 YAPC::Kyoto 主講者 &lt;a href="https://twitter.com/yasuhiro_onishi/"&gt;yasuhiro_onishi&lt;/a&gt; 與最佳演講得獎者 &lt;a href="https://twitter.com/ar_tama/"&gt;ar_tama&lt;/a&gt; 兩人都在臺上講到,十幾年前某年參加 YAPC::Asia 時忘了帶票去而在報告處讓主辦者通融一下而得以繼續參與研討會活動。這顯然是參與一般研討會是碰不到的人情表現。YAPC 研討會的主辦者也全都是 Perl 社群生態系內的人,才知道在當下通融放人入場並不是甚麼壞事。畢竟大部分的神社參拜者也都是只帶著誠意空手而去的。偶爾通融放沒有持票的人入場,也其實有助於社群的活絡與成長。而且說不定他們就會在幾年之後的研討會講臺上感謝當年的主辦者了。 &lt;/p&gt;&lt;p&gt;某種意義上 YAPC 似乎也就像是さくらパレード那種聯合多間學校舉辦的遊行活動一樣。YAPC 就是由多個 Perl 社群撐起來的一種草根研討會。當然通常還是由幾個主辦人張羅所有事情,但來自各處的小社群、Perl Mongers、也各自出力。像是在午餐時間錄 Podcast 的、或是把現場講臺直播出去的、或是像這個其他房間直播「&lt;a href="https://www.youtube.com/watch?v=T2AMMhqMnNc"&gt;裏 Talk&lt;/a&gt;」的這個 大井町.PM 也是替 yapcjapan 出了很多力的社群。而且他們還做了一支很有某節目閒扯淡風格的&lt;a href="https://www.youtube.com/watch?v=Rlz2ZsXWNlo"&gt;贊助商影片&lt;/a&gt;。看來似乎毫無重點。不過有時候社群就是這樣,在很輕鬆的時間裡面讓一些甚麼和事情能夠推進一些。 &lt;/p&gt;&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/T2AMMhqMnNc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen&gt;&lt;/iframe&gt; &lt;iframe width="560" height="315" src="https://www.youtube.com/embed/Rlz2ZsXWNlo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen&gt;&lt;/iframe&gt; &lt;p&gt;如果真要爲本文做個像樣的結論的話,那麼:各位研討會主辦者啊,如果有人說他忘了帶票,千萬不要對他太嚴格喔。或許十年後會變成一段佳話呢。 &lt;/p&gt;&lt;p&gt;&lt;script async charset="utf-8" src="//embedr.flickr.com/assets/client-code.js"&gt;&lt;/script&gt; &lt;/p&gt;</content> <category term="yapcjapan"/> <category term="kyoto"/> <category term="travel"/> </entry> <entry> <id>https://gugod.org/2023/03/perlx-scopefunction-0.03/?fe3ad324349663bbc5baa702ba551ac6d375c060</id> <link rel="alternate" href="https://gugod.org/2023/03/perlx-scopefunction-0.03/" type="text/html"/> <title>PerlX::ScopeFunction 0.03 釋出</title> <published>2023-03-17T09:41:28+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p><a href="https://metacpan.org/release/GUGOD/PerlX-ScopeFunction-0.03">https://metacpan.org/release/GUGOD/PerlX-ScopeFunction-0.03</a> </p> <p>好幾年前我擅自開始把 PerlX:: 這個 namespace 當成是「Perl 語言的延伸」的 意義在使用,並且做了一些有的沒的新語法。最近這星期做了 PerlX::ScopeFunction。 </p> <p>這個模組提供兩個新的語法關鍵字: let 與 with。 </p> <p>先看範例,就能大致上掌握這兩個關鍵字的用法: </p> <pre> <code>use v5.36; use List::Util qw( sum0 ); use List::MoreUtils qw( part minmax ); use PerlX::ScopeFunction qw(let with); my @input = (3,1,3,3,7); let ( ($min,$max) = minmax(@input); $mean = sum0(@input)/@input ) { say "$min &lt;= $mean &lt;= $max"; } with ( part { $_ % 2 } @input ) { my ($evens, $odds) = @_; say "There are " . scalar(@$evens) . " even numbers: " . join(" ", @$evens); say "There are " . scalar(@$odds) . " odd numbers: " . join(" ", @$odds); } </code> </pre> <p>這兩個關鍵字提供了一種可以將幾個指定變數的語義範圍縮限起來的方式。前述範 例中 let 語句所造出的 $min、$max、$mean 三個變數的語義範圍是在後方的區塊 之內。with 語句則是能將一個算式取值,並把結果裝入 @_ ,使其能在後方的區塊內使 用。 </p> <p>這兩種語法結構都是從其他語言借過來的,在 Perl5 目前的語法中,最類似的是 sub closure 與 <code>do</code>: </p> <pre> <code>sub { my ($evens, $odds) = @_; ... }-&gt;(part { $_ % 2 } @input); do { my ($min,$max) = minmax(@input); my $mean = sum0(@input)/@input; ... }; </code> </pre> <p>而 PerlX::ScopeFunction 所做的就是提供一些新關鍵字,讓這種特殊片語寫起來 更加明瞭一些,也利於解讀。 </p> </div> </content> <category term="perl"/> <category term="cpan"/> </entry> <entry> <id>https://gugod.org/2023/02/steam-deck-as-a-workstation/?26d67e9fe4ccf78af14e65f575cce77f7a94eba1</id> <link rel="alternate" href="https://gugod.org/2023/02/steam-deck-as-a-workstation/" type="text/html"/> <title>把 Steam Deck 調到適合做部分工作</title> <published>2023-02-25T00:39:48+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>Steam Deck 的桌面模式基本上就是個 KDE Plasma 界面,拿來做不少工作很是夠用。 </p> <p>本文描述的幾項重點爲: </p> <ol> <li>建立工作專用帳號 <code>work</code>。 </li> <li>以 <code>work</code> 身份而安裝 <code>distrobox</code> 並開設虛擬機。 </li> <li>調整虛擬機內外環境變數,使 GUI 程式也可顯示在桌面環境上,並能與桌面環境的 Fcitx 輸入法框架互通。 </li> </ol> <h2>粗略想法 </h2> <p>基本上直接使用 Steam OS 的「桌面模式」。在不做大幅度修改的前提之下,就可以完成不少工作事項。 </p> <p>在切換到桌面模式之後,右搖桿可當滑鼠來使用。R2 對應到滑鼠左鍵,L2 對應到滑鼠右鍵(注意:左右相反)。外出時接個好打的鍵盤,就可以進行不少文字工作。只是,一直低頭看小螢幕實在傷頸酸肩,最好還是準備個能將機器墊高一些的支架或站台, </p> <p>這 Steam OS 提供的桌面模式有以下幾點不那麼容易克服的限制: </p> <ul> <li>透過機器上左手邊的 "Steam" 按鈕進入桌面模式時,相當於登入 <code>deck</code> 這個帳號,並且不必輸入密碼就可以登入。 </li> <li><code>deck</code> 帳號是 <code>wheel</code> 管理員群組的一員,而且 <em>無法</em> 爲其設定登入密碼。 </li> <li>系統用目錄全部爲唯讀的。在不透過指令修改檔案系統設定的前提之下,使用者只能自由修改 /home 以下目錄。 </li> <li>軟體安裝固定使用 flatpak 架構。只能安裝在 flathub 上登記有案的軟體套件。不過,可以自行添加任意 flathub 目錄站,。 </li> <li>系統更新後,系統用的目錄內容會全面被換掉。任何能把唯讀目錄區改掉的手法所造成的變更都活不過系統更新。 </li> </ul> <p>由於我還是會把 Steam Deck 拿來玩遊戲,所以基本上不會去試着突破以上這幾個限制,也不會嘗試去重新安裝成慣用的 Linux。附帶一提, 有人成功在 Steam Deck 上裝了 Windows,姑且算是個選項。 </p> <p>在不破壞前述幾項限制的前提之下,基本上能有的選項是: </p> <ol> <li>只用 flathub 上現有的軟體,看能做到什麼地步。 </li> <li>跑虛擬機,直接在其內部建構整套工作站環境。 </li> <li>以上兩者的混合。 </li> </ol> <p>以軟體開發爲目的話,大致上會需要 </p> <ol> <li>文字編輯器 (Emacs, vim, ......) </li> <li>程式碼編譯器 (clang, rustc, perl, ruby, ......) </li> <li>諸多函式庫,隨時要能安裝與更新 </li> <li>能測試編譯結果的執行環境 </li> </ol> <p>flathub 上的軟體能提供文字編輯器,但要安裝其他三項都不那麼容易。因此必須使用虛擬機。 </p> <p>目前爲止試過能較快上手的是 distrobox -- 這基本上是依賴 podman,以及現有的 container 生態系統去快速做出新的 Linux 環境。 </p> <p>使用 podman 的主要原因它有提供特殊版本。讓 podman 本身可以裝在 <code>$HOME</code> 底下,所有執行時需要的資料等等也都放在 <code>$HOME</code> 底下。對於 Steam Deck 這種特殊的系統而言是十分有利的。只要能裝在 <code>$HOME</code> 底下,就可以活過系統更新,不必重新安裝。 </p> <p>以 distrobox 所準備出來的虛擬機有個不錯的特性:可以將任意目錄指定爲虛擬機內的家目錄,並且以 bind mount 方式讓內外的檔案系統直接互通。也就是說,在桌面環境下其啓動的文字編輯器也可以直接去修改 distrobox 內部的家目錄內容,只讓編譯與測試在虛擬機內完成。這需要對指令有一定的熟練度,似乎對 IDE 不太友善。但至少是個不錯的辦法。真的需要 IDE 的話,也可在虛擬機內全套裝好。 </p> <h2>建立工作專用的帳號 </h2> <p>建立工作用帳號的主要目的是便於區分家目錄底下的內容。讓 <code>deck</code> 帳號底下的內容全都是與遊戲相關的,並讓工作用帳號底下的內容全都是與工作相關的。 </p> <p>雖然根目錄是唯讀的,但是仍然可以透過指令或 KDE Plasma GUI 來建立其他使用者帳號,並且也能夠活過系統更新。只是,自遊戲模式切換到桌面模式時,固定是登入為 <code>deck</code> 帳號,<em>無法</em> 爲其設定登入密碼,也無法切換成其他使用者。只能開終端機出來用 <code>su</code> 變身成其他帳號。但這樣也就夠了。 </p> <p>假設工作用帳號爲 <code>work</code> ,那便以 <code>deck</code> 身份執行以下幾行指令來建立這個新帳號: </p> <pre> <code>useradd -U -m work</code> </pre> <p>建好之後可用 <code>sudo</code> 或 <code>su</code> 來變身: </p> <pre> <code>sudo su - work</code> </pre> <h2>開設工作用虛擬機 </h2> <p>變身成爲 <code>work</code> 之後,首先是安裝 distrobox。依照 <a href="https://github.com/89luca89/distrobox#installation">distrobox README.md 內的安裝說明</a>,執行以下指令可將 distrobox 安裝到 <code>~/.local</code> 底下: </p> <pre> <code>curl -s https://raw.githubusercontent.com/89luca89/distrobox/main/install | sh -s -- --prefix ~/.local</code> </pre> <p>安裝好後 <code>distrobox</code> 這個執行檔就會被放在 <code>~/.local/bin</code> 底下。 </p> <p>再來是安裝 <code>podman</code> -- 同樣也是要安裝到 <code>~/.local</code> 底下去。依照 <a href="https://github.com/89luca89/distrobox/blob/main/docs/compatibility.md#install-podman-in-a-static-manner">distrbox 文件</a> ,使用他們提供的 <code>install-podman</code> 腳本就可以: </p> <pre> <code>curl -s https://raw.githubusercontent.com/89luca89/distrobox/main/extras/install-podman | sh -s -- --prefix ~/.local</code> </pre> <p>如此一來 <code>podman</code> 全體會被放在 <code>~/.local/podman/</code>,而 <code>podman</code> 這個執行檔則是會被放在 <code>~/.local/podman/bin</code>。 </p> <p>最後是調整 <code>PATH</code> 變數內以便日後執行。慣例是在 <code>~/.profile</code> 裡加入類似以下這一行的指令: </p> <pre> <code>export PATH=~/.local/bin:~/.local/podman/bin:$PATH</code> </pre> <p>最後就是實際上建出工作用虛擬機。假設要使用 alpine:latest 這個 container image,並將虛擬機命名爲 <code>workstation</code>,且將虛擬機內的家目錄指定爲 <code>~/distrobox/workstation/home</code> 的話,就是這行指令: </p> <pre> <code>distrobox create --image alpine:latest --name workstation --home ~/distrobox/workstation/home</code> </pre> <p>如果不指定的話,預設家目錄就是跟 <code>$HOME</code> 一樣。但這樣一來虛擬機內所有程式的設定檔路徑都會跟機主 (Steam Deck) 的路徑相同。如果要開設多個虛擬機,可能會遇到設定檔或暫存檔互相衝突的問題。建議是給每個虛擬機自己一個專用的家目錄。機主家目錄 <code>$HOME</code> 會以 bind mount 的方式直接與虛擬機內互通。所以也不至於造成太多不便。 </p> <p>建好之後就可以進入虛擬機內逛逛了: </p> <pre> <code>distrobox enter workstation</code> </pre> <h2>讓虛擬機的 GUI 程式顯示在桌面環境上 </h2> <p>目前 Steam Deck 桌面環境是 Xorg,也就是說,其實也能加入一些調整,讓 distrobox 虛擬機內的 GUI 程式(如 Firefox)直接顯示在桌面環境上。 </p> <p>桌面環境:需要以 <code>xhost</code> 指令去讓跑在其他地方的 X client 可以在本機開視窗出來。以我的設定方式,所謂的「其他地方」是本機上的其他使用者。包括由虛擬機內開出來的 GUI 程式。 </p> <p>假設工作用帳號是 <code>work</code> ,那便在 <code>/home/deck/.bash_profile</code> 內加入以下幾行指令: </p> <pre> <code>xhost +SI:localuser:work alias work='sudo --preserve-env=DISPLAY su -w DISPLAY - work</code> </pre> <p>依照這兩個月的使用經驗,<code>DISPLAY</code> 有時是 <code>:0</code> 有時是 <code>:2</code>,不是很確定爲何改變。但總之只要讓所有地方的 <code>DISPLAY</code> 都有正確地設定好就好。方法就是在以 <code>sudo</code> 變身時把目前的 <code>DISPLAY</code> 保留下來。 </p> <p>如此一來便能夠在 WezTerm 內以 <code>work</code> 爲切換到工作用帳號的指令。切換過去後,進入虛擬機: </p> <pre> <code>distrobox enter workstation</code> </pre> <p>並在虛擬機內直接執行 GUI 程式指令,例如 Firefox: </p> <pre> <code>firefox &amp;</code> </pre> <p>過幾秒鐘後便可以看到 Firefox 視窗開出來了。 </p> <p>附帶一提,由此方法開出來的 GUI 視窗也是可以配合桌面環境上的 Fcitx 輸入法框架來輸入漢字。如果有程式對輸入法切換熱鍵沒反應,那就檢查看看 <code>LANG</code> 環境變數是否有設定爲 <code>zh_TW.UTF-8</code>。有些程式不一定需要 <code>LANG</code> 爲 <code>zh_TW.UTF-8</code>,只要是某個有效的值(有對應到存在於系統上的 <code>locale</code> 資料),設定爲 <code>en_US.UTF-8</code> 或許也可以。 </p> </div> </content> <category term="SteamDeck"/> </entry> <entry> <id>https://gugod.org/2023/02/steam-deck-desktop-fcitx-input-method/?4e1119b246a29b6cc29469bae4edcc0be2098696</id> <link rel="alternate" href="https://gugod.org/2023/02/steam-deck-desktop-fcitx-input-method/" type="text/html"/> <title>在 Steam Deck 桌面模式中使用 fcitx 輸入法框架</title> <published>2023-02-23T20:08:22+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>Steam Deck 桌面模式就是 KDE Plasma 圖形化介面。但出廠附上的輸入法設定是 ibus 框架的,其內附的漢語拼音等輸入法對我個人而言不太合用。 </p> <p>於是,參考 <a href="https://brli.github.io/2022/12/23/steam-deck-cjk-input.html">BrLi 的方法</a> 後裝了 fcitx 框架,並且修改了相關設定,讓進入桌面模式後,就能直接起動 fcitx 而且不會起動 ibus。重點步驟如下: </p> <ol> <li>在 "Discover" app 中找到 fcitx5 框架與輸入法本體後立刻安裝。 </li> <li>讓 fcitx5 自動於進如桌面模式時起動 </li> <li>編輯 <code>~/.config/plasma-workspace/env/input.sh</code> 這個檔案,貼入如後內容。 </li> <li>將 Steam Deck 重新開機後,再次進入桌面模式 </li> </ol> <p>讓 fcitx5 自動起動的方式是把其起動腳本複製一份到 <code>~/.config/autostart</code> 這個路徑底下去: </p> <pre> <code>cp /home/.steamos/offload/var/lib/flatpak/exports/share/applications/org.fcitx.Fcitx5.desktop ~/.config/autostart/</code> </pre> <p>而 <code>~/.config/plasma-workspace/env/input.sh</code> 內容為: </p> <pre> <code>export GTK_IM_MODULE=fcitx export QT_IM_MODULE=fcitx export XMODIFIERS=@im=fcitx export XIM=fcitx</code> </pre> <p>如此一來在進入桌面模式後,於右下角工具列上會出現一個 Fcitx 的圖示。會顯示目前輸入法的狀態,並且可以透過點擊此圖示來設定各項細節。 </p> <p>核心的輸入法方面,為了配合手邊的 40% 鍵盤,我目前主要是使用 RIME 中的朙月拼音來滿足輸入漢字的需求。但想必也能接上其他種類的輸入法。 </p> </div> </content> <category term="SteamDeck"/> </entry> <entry> <id>https://gugod.org/2023/02/steam-deck-download-folder-of-dlc/?61a0524247d0dd201a6264eb30b03de342fdda21</id> <link rel="alternate" href="https://gugod.org/2023/02/steam-deck-download-folder-of-dlc/" type="text/html"/> <title>Steam Deck DLC 檔案路徑</title> <published>2023-02-22T09:44:28+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>目前在購買遊戲 DLC (主要是原聲帶)後似乎無法於 Steam Deck 遊戲模式界面底下播放,但可以在進入桌面模式後,開桌面模式的 Steam 程式、找到遊戲 DLC 頁面,然後使用其內建的播放器來播放。 </p> <p>不過、在 Steam 程式界面內逛索,在找到 DLC 在的位置就會令 GUI 路癡迷路了。如果能夠順利找到 DLC 頁面,下載完畢之後可以按下「瀏覽本機檔案」按鈕,將音樂檔案複製到別的地方,給慣用的 VLC 播放器去播放。 </p> <p>稍微調查了一下後發現如果是遊戲原聲帶,其實下載位置必定是在以下兩個路徑底下: </p> <ul> <li>內部磁碟: /home/deck/.local/share/Steam/steamapps/music/ </li> <li>SD 卡: /run/media/mmcblk0p1/steamapps/music/ </li> </ul> <p>我的 SD 卡的路徑名爲 /run/media/mmcblk0p1,不確定這個名稱是否固定,或許換張卡就會改變。 </p> <p>初步看來是這兩個路徑底下還會依照 DLC 名稱分資料夾出來。來自不同 DLC 的音樂檔案不會混合在一起。 </p> <p>接下來就是開 VLC ,並把那兩個路徑直接加到 Media Library 中。VLC 會自行掃描整個路徑底下、可以自動找到所有音樂檔案。也可以省下在 Steam GUI 中迷路的時間。 </p> </div> </content> <category term="SteamDeck"/> </entry> <entry> <id>https://gugod.org/2023/01/perl-howto-list-upgradable-cpan-modules/?060b346b1b8b912642327b353d759f468bb27862</id> <link rel="alternate" href="https://gugod.org/2023/01/perl-howto-list-upgradable-cpan-modules/" type="text/html"/> <title>[Perl] 如何列出可升級的 CPAN 模組</title> <published>2023-01-05T10:23:09+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>一陣子之前看到的。 <a href="https://metacpan.org/dist/cpan-outdated">cpan-outdated</a> 這個指令,能列出所有可升級的模組。 </p> <p>它的輸出格式看來是 CPAN Mirror 底下的路徑。可以直接餵給 cpanm 去安裝。 </p> <pre> <code># cpan-outdated | head P/PL/PLICEASE/Alien-Build-2.76.tar.gz P/PL/PLICEASE/Alien-Libxml2-0.19.tar.gz T/TO/TOKUHIROM/Amon2-6.16.tar.gz R/RJ/RJBS/App-Cmd-0.335.tar.gz O/OA/OALDERS/App-perlimports-0.000049.tar.gz R/RJ/RJBS/App-Uni-9.006.tar.gz P/PJ/PJACKLAM/bignum-0.66.tar.gz L/LE/LEEJO/CGI-4.55.tar.gz G/GA/GARU/Clone-0.46.tar.gz P/PM/PMQS/Compress-Raw-Bzip2-2.201.tar.gz</code> </pre> <p>此外既有的 <code>cpan</code> 指令也能做到類似的事:執行 <code>cpan -O</code> 後,會列出各模組的目前版號以及最新版的版號。 </p> <pre> <code># cpan -O | head -15 Reading '/home/gugod/.cpan/Metadata' Database was generated on Thu, 05 Jan 2023 00:54:02 GMT Module Name Local CPAN ------------------------------------------------------------------------- CPAN: Module::CoreList loaded ok (v5.20220520) Acme::CPANAuthors::Austrian 1.1318 1.1318 Alien::Base 2.5100 2.7600 Alien::Base::PkgConfig 2.5100 2.7600 Alien::Base::Wrapper 2.5100 2.7600 Alien::Build 2.5100 2.7600 Alien::Build::CommandSequence 2.5100 2.7600 Alien::Build::Interpolate 2.5100 2.7600 Alien::Build::Interpolate::Default 2.5100 2.7600 Alien::Build::Log 2.5100 2.7600 Alien::Build::Log::Abbreviate 2.5100 2.7600</code> </pre> <p>但看來 <code>cpan -O</code> 列出的是 package 而 <code>cpan-outdated</code> 列出的是 distribution。 不過也可執行 <code>cpan-outdated -p</code>,讓它改列 package 名。 </p> <p>如果只是要無條件全部升到最新版的話,可以執行 <code>cpan -U</code> 或是 <code>cpan-outdated | cpanm</code>。 </p> </div> </content> <category term="perl"/> <category term="cpan"/> <category term="howto"/> </entry> <entry> <id>https://gugod.org/2023/01/2022-year-review/?41b8ff2e0f6712a3dc70249603683c0ccb0de032</id> <link rel="alternate" href="https://gugod.org/2023/01/2022-year-review/" type="text/html"/> <title>2022 年度回顧</title> <published>2023-01-01T16:53:33+09:00</published> <author> <name>gugod</name> </author> <content type="xhtml" xml:base="https://gugod.org"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>2022 這一年度的變化還真是不少。 </p> <p>放假與觀光:稍微做了些簡單的旅行。多是一天就結束的,但也有幾次比較長期的。相對與去年與前年是多了幾回,但對於 COVID-19 的盛行還是放心不下,依然是小心翼翼地在外出。也由於一直沒有長期旅行而累積了不少休假日,而決定以「每個星期都請一天假」的方式來消化那些假日。讓自己連續四、五星期都是週休三日。並且把休假日放在週一或週五。放在週一的好處是可以去電影院,並且在完全沒有人潮的狀態下看電影,然後在同樣是沒有人潮的狀態下逛街。其實也是個消解壓力的不錯的方式。 </p> <p>舊物清理:在回到父母家時順便把閒置著的房間努力地大掃除了兩遍。除了掃去厚厚的灰塵以外,也把很多東西脫手了。一來是把不少擺到變成電子廢棄物的舊線材與舊器材等全部翻出來送去資源回收,二來是把一些還可以用的拿去給二手商店代售。賣幾多錢都無所謂,既然是還能用的東西,與其直接丟棄,不如讓給下一個使用者來用看看。有好幾項是十歲以上的舊蘋果電腦產品,拿去 Apple Store 回收是連店員也沒看過,變成好像我在給 Apple Store 店員展示 Apple 產品的狀態。 </p> <p>拜見甘露水:撥空前去欣賞了「甘露水」以及那代的藝術家們的作品。也拜訪翻修完成了的嘉義市立美術館欣賞陳澄波作品,以及那棟名建築。雖然僅是不太深入地看看,但似乎也能讓腦袋受到刺激與啓發。雖然這只是一年 365 日之中僅僅兩個半天的事情,但都是令人印象深刻的展覽。定期逛逛美術館,主動去看看那些美麗的靜態螢幕保護程式(?),似乎也有助於把長期佔在腦內的那些雜物給沖走,將腦袋中的「桌面圖示」一次清光。 </p> <p>主力個人工作電腦的改變:在歷經三次修理之後,自 2013 年左右用到 2021 年年底的 Macbook Air 總算是壞到不能更壞了。這次連開機過程都進不去,電源啓動後播放出 Sosumi 音效後就一直停在黑底白蘋果畫面,成爲只能顯示蘋果商標的機器了。努力嘗試救援後發現還能開進 Target disk mode 讓我把資料盡數救出,算是幸運。自然,這本筆電也是送去給 Apple Store 回收了。自回收之後,一直還沒有決定是否要再買筆電而就這麼過了大半年,一直都是以一台 Raspberry Pi 4 當做個人用工作機。以寫文章與簡單的開發而言還算夠用。雖然在瀏覽網頁這件事上勝不過 Android 手機(爲何這年頭網頁用起來如此的重歪歪?),但如果儘量不去開瀏覽器「閒逛」,倒也能完成不少事情。遲遲沒有再買筆電的原因之一是沒有需求:在外出時間減到最低的狀態下,根本不會像以前那樣拿著筆電去咖啡館使用。原因之二是我預期要把 SteamDeck + Cutie Pi 拿來當成工作機組合來用。只是不巧筆電提早壞去了。在年底收到 SteamDeck 後花了不少時間在弄懂如何在上面設置一套適合自己的工作環境。雖然 SteamDeck 有提供桌面模式,但有不少眉眉角角的地方得要注意。好在自己早已習慣於純文字工作環境,就算不把 SteamDeck 桌面模式徹底改掉,開個可以打指令的終端機出來其實也就夠用。但不得不讚歎一下:Valve 還真是把 SteamDeack 各處弄得妥妥善善的啊。 </p> <p>隨著前述工作機器上的變化,我決定開始重新定義一下自己與電腦之間的關係。由於公司政策改爲鼓勵遠端工作已經兩年,似乎也很有可能在 COVID19 盛行「宣告」結束之後繼續維持讓多數員工遠端作業,可以想見在家時間一直都會很長。偶爾會發生無意識地把電腦打開來,卻沒有要先想好要完成甚麼工作,變成常常有坐在電腦前面 30 分鐘,卻好像只是在檢查郵件、Slack、GitHub 通知,把四處出現的紅點通知給消除了,而實質上卻是只讀進而不產出,好像甚麼都沒有完成的這種狀況。由於這直接影響到了工作效率,必須想辦法改善纔行。自己想到的方法,是讓自己在開電腦時必定要完成一些事項,並且在完成後立刻把電腦關機。不是進入睡眠模式,而是關閉電源。在開電腦之前,先把此刻要完成的事項寫在面前的筆記本上,並且時刻意識到動作步驟。例如,先想好要改 BUG-123 要開哪幾個檔案,大致上要改那幾個函式,要補充那些文件之類等之類的這類動作。然後開電腦後就依照剛剛想好的步驟照做。這其實頂麻煩的,而且效果並不立竿見影(還是很容易分心),但似乎無意間增強了在腦內寫程式的能力。一定程度上這也直接影響到筆記這件事。既然開電腦的時間減少了,手寫筆記的次數就增加了。但我反正本來就是以簡單的子彈筆記的形式用紙筆在做工作追蹤與記錄的,頂多就只是筆記本消耗速度變快了一些,並不是一件很不習慣的事。 </p> <p>刻意增加看書時間:無論是紙本書或是電子書。由於住處附近不遠處就有圖書館,因此就每兩週去借個幾本書來翻。但這方面是完全沒有替自己設定「業績」。就算是借回來放在桌上放到最後一頁都沒翻,也不要讓自己覺得愧疚。可能是由於有這樣的心態建設,反而讓每本書都有進度。雖然實質上每本書都沒有 100% 讀完,有不少只細讀了 5% 左右,但是至少都有快速翻過,有把握住大綱。這種不求精實度的懶散做法似乎不錯,至少讓我能夠開始花比以前更多的時間在讀書這件事情上,而有個起頭後,如果真的因那起頭的 5% 的內容而對書本省下的 95% 產生了興趣,那就自然而然會多讀幾頁。內容類型不限,去圖書館當天想看甚麼就借甚麼。一定程度上也有助於將自己的舒適圈擴得更大。這刻意看書的習慣,也有助於減少 SNS 的無意識的使用。如果讓看書、滑 SNS、開電腦等日常的做爲都變成是有意識的行動,那麼自然就沒有時間會在無意間消失了。 </p> <p>隨著電腦使用習慣的改變而多出來的那麼一點點時間,拿來稍微翻幾頁書,也算是不錯的。如果順便有撿到一些名言佳句那就令人高興,但就算沒有,也不會太在意。這似乎有點像是在看 YouTube 影片的時候以略看縮圖的方式挑片段看。先快速瀏覽,抓個大意,如果有碰到似乎有點意思的片段,再放慢速度。 </p> <p>認養小貓兩隻:兩隻都是從幼貓開始養。看著小貓從快速的在三個月時間內從幼小體型長成接近成貓體型,實在是不得不讓人再次覺得:人體成長期真是沒有效率啊。同時也覺得:幼貓用手來抓東西的動作真是十分靈活,只要是碰觸得到的到物件大概都會被當成足球(手球?)撥來撥去。或許真的可以期待貓科動物演化出對向指,讓人類在進化這件事情上開始退休。 </p> <p>重新認識住家週邊環境:既然不打算遠行,也不必通勤上班。那就把通勤時間拿來在住家周圍散步。並且偶爾以步行走三、四公里到稍微有點距離的地方探險一下。即便只是週末專門步行到某間餐廳去喫一頓就回家,把原本只要 15 分鐘車程的事花一個下午的時間來做,讓過程大於結果。挑各種不同的小路走,觀察路上的變化,是一件頂有意思的事。說不定還無意讓玩 geoguesser 的能力提升了一些。 </p> <p>部落格文章的舊去新來:把部落格站上一些舊到變得很好笑的文章給清除了,也把近年來對 Raku 語的學習整理了一下,以「Raku 如何如何」這種形式做了一些文章。有部分只是把過去以 Perl 6 爲題的文章重新編譯過而已。在內容方面只能算是自己的學習筆記,說不上完整。不得不說 Raku 語真的是一門很容易學的語言,各種表示式很一致,幾乎沒有甚麼怪怪的地方,算式形式雖然多,但語法規則卻不多,只要遵循幾條規則就可以看懂大部分的程式碼,雖然跟其他語言命名慣例未必一致,內建的各類別語方法的名稱也很好記。學習 Raku 之外,偶爾也稍微學習一些其他新舊程式語言與一些數學知識。 </p> <p>林林總總地列舉了不少,光是坐在桌前就可以回憶出這麼多重要變化,可見 2022 年真的是很重要。(雖然每一年都是一樣重要的啦。) </p> </div> </content> <category term="YearReview"/> </entry> <updated>2025-01-30T20:59:24+08:00</updated> </feed>

Pages: 1 2 3 4 5 6 7 8 9 10