From 13b159c6dd499b5c67a110e02780d9e741f0ecdb Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 24 Feb 2025 06:27:07 +0900 Subject: feat(blog/nuldoc): do not insert whitespace to linebreaks between Japanese sentences --- vhosts/blog/nuldoc-src/renderers/html.ts | 11 ++- .../posts/2021-03-30/phperkaigi-2021/index.html | 58 ++++++------- .../index.html | 20 ++--- .../python-unbound-local-error/index.html | 14 ++-- .../ruby-detect-running-implementation/index.html | 12 +-- .../ruby-then-keyword-and-case-in/index.html | 28 +++---- .../rust-where-are-primitive-types-from/index.html | 32 ++++---- .../index.html | 18 ++--- .../vim-swap-order-of-selected-lines/index.html | 28 +++---- .../2022-04-09/phperkaigi-2022-tokens/index.html | 94 +++++++++++----------- .../index.html | 32 ++++---- .../posts/2022-05-01/phperkaigi-2022/index.html | 48 +++++------ .../php-conference-okinawa-code-golf/index.html | 22 ++--- .../index.html | 18 ++--- .../index.html | 80 +++++++++--------- .../phperkaigi-2023-unused-token-quiz-1/index.html | 36 ++++----- .../setup-server-for-this-site/index.html | 44 +++++----- .../phperkaigi-2023-unused-token-quiz-2/index.html | 40 ++++----- .../phperkaigi-2023-unused-token-quiz-3/index.html | 40 ++++----- .../rewrite-this-blog-generator/index.html | 28 +++---- .../index.html | 52 ++++++------ .../2023-04-04/phperkaigi-2023-report/index.html | 42 +++++----- .../2023-06-25/phpconfuk-2023-report/index.html | 18 ++--- .../compile-php-runtime-to-wasm/index.html | 70 ++++++++-------- .../index.html | 6 +- .../public/posts/2023-12-03/isucon-13/index.html | 18 ++--- .../posts/2023-12-31/2023-reflections/index.html | 8 +- .../index.html | 20 ++--- .../index.html | 26 +++--- .../2024-02-10/yapcjapan-2024-report/index.html | 8 +- .../2024-02-22/phpkansai-2024-report/index.html | 8 +- .../2024-03-17/phperkaigi-2024-report/index.html | 26 +++--- .../posts/2024-03-20/my-bucket-list/index.html | 16 ++-- .../phpcon-odawara-2024-report/index.html | 20 ++--- .../pipefail-option-in-gitlab-ci-cd/index.html | 32 ++++---- .../index.html | 20 ++--- .../2024-05-11/phpconkagawa-2024-report/index.html | 24 +++--- .../2024-06-19/scalamatsuri-2024-report/index.html | 14 ++-- .../reparojson-fix-only-json-formatter/index.html | 24 +++--- .../index.html | 24 +++--- .../posts/2024-09-28/mncore-challenge-1/index.html | 12 +-- .../posts/2024-12-04/cohackpp-report/index.html | 22 ++--- .../posts/2024-12-33/2024-reflections/index.html | 8 +- .../phperkaigi-2023-tokens-q1/index.html | 74 ++++++++--------- .../index.html | 16 ++-- .../phpcon-nagoya-2025-report/index.html | 12 +-- 46 files changed, 665 insertions(+), 658 deletions(-) (limited to 'vhosts/blog') diff --git a/vhosts/blog/nuldoc-src/renderers/html.ts b/vhosts/blog/nuldoc-src/renderers/html.ts index 4ebc342e..cdfc4c24 100644 --- a/vhosts/blog/nuldoc-src/renderers/html.ts +++ b/vhosts/blog/nuldoc-src/renderers/html.ts @@ -148,8 +148,15 @@ function textNodeToHtmlText(t: Text, ctx: Context): string { const s = encodeSpecialCharacters(t.content); if (ctx.isInPre) return s; - // TODO: 日本語で改行するときはスペースを入れない - return s.replaceAll(/\n */g, " "); + return s.replaceAll(/\n */g, (_match, offset, subject) => { + const last_char = subject[offset - 1]; + if (last_char === "。" || last_char === "、") { + // 日本語で改行するときはスペースを入れない + return ""; + } else { + return " "; + } + }); } function encodeSpecialCharacters(s: string): string { diff --git a/vhosts/blog/public/posts/2021-03-30/phperkaigi-2021/index.html b/vhosts/blog/public/posts/2021-03-30/phperkaigi-2021/index.html index f10832af..4dfee57e 100644 --- a/vhosts/blog/public/posts/2021-03-30/phperkaigi-2021/index.html +++ b/vhosts/blog/public/posts/2021-03-30/phperkaigi-2021/index.html @@ -67,15 +67,15 @@

PHPerKaigi 2021 参加レポ

- 2021-03-26 から 2021-03-28 にかけて開催された、 PHPerKaigi 2021 に一般参加者として参加した。 弊社 デジタルサーカス株式会社 (今年1月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。 + 2021-03-26 から 2021-03-28 にかけて開催された、 PHPerKaigi 2021 に一般参加者として参加した。弊社 デジタルサーカス株式会社 (今年1月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。

- このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。 + このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。

- 発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。 + 発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。

@@ -148,15 +148,15 @@

- AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。 + AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。

- PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。 + PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。

- 勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。 + 勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。

@@ -223,7 +223,7 @@

- SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。 + SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。

@@ -315,7 +315,7 @@

- つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。 + つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。

@@ -326,7 +326,7 @@

- 個人的に楽しみだった発表。 + 個人的に楽しみだった発表。

@@ -406,7 +406,7 @@

- 期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。 この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。 + 期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。

@@ -557,7 +557,7 @@

- User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。 高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。 + User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。

@@ -568,7 +568,7 @@

- 型のある世界で生きてきた身として大いに楽しみにしていた発表。 + 型のある世界で生きてきた身として大いに楽しみにしていた発表。

@@ -612,14 +612,14 @@

- 昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。 今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。 + 昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。

12:30 [A]

- 昼食をとっていた。事前に何か食料を買っておくべきだった。 + 昼食をとっていた。事前に何か食料を買っておくべきだった。

@@ -630,7 +630,7 @@

- この発表も以前から非常に楽しみにしていた。 + この発表も以前から非常に楽しみにしていた。

@@ -692,7 +692,7 @@

- ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。 + ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。

@@ -703,7 +703,7 @@

- 全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。 + 全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。

@@ -835,15 +835,15 @@

- PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。 + PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。

- 個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。 + 個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。

- PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。 + PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。

@@ -854,7 +854,7 @@

- Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。 + Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。

@@ -919,7 +919,7 @@

- (発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。 + (発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。

@@ -986,30 +986,30 @@

Day 2 (2021/03/28)

- 冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。 + 冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。

- 残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。 + 残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。

全体の感想

- Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。 + Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。

- 今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。 + 今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。

- 1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 まあ初カンファレンスだし、とお茶を濁しておこう。 + 1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。まあ初カンファレンスだし、とお茶を濁しておこう。

- さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。 + さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。

@@ -1022,7 +1022,7 @@

- ではまた来年。 + ではまた来年。

diff --git a/vhosts/blog/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html b/vhosts/blog/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html index c8ee5e14..b6baad39 100644 --- a/vhosts/blog/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html +++ b/vhosts/blog/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html @@ -66,12 +66,12 @@ NOTE
- この記事は Qiita から移植してきたものです。 元 URL: https://qiita.com/nsfisis/items/94090937bcf860cfa93b + この記事は Qiita から移植してきたものです。元 URL: https://qiita.com/nsfisis/items/94090937bcf860cfa93b

- タイトル落ち。まずはこのコードを見て欲しい。 + タイトル落ち。まずはこのコードを見て欲しい。

#include <iostream>
@@ -105,11 +105,11 @@
           
            
           

- この記事から得られるものはこれ以上ないので以下は蛇足になる。 + この記事から得られるものはこれ以上ないので以下は蛇足になる。

- 別件で cppreference.com の identifier のページ を読んでいた時、次の文が目に止まった。 + 別件で cppreference.com の identifier のページ を読んでいた時、次の文が目に止まった。

@@ -126,22 +126,22 @@

- キーワードでも属性として指定する場合は非キーワードとして使えるらしい。 実際にやってみる。 + キーワードでも属性として指定する場合は非キーワードとして使えるらしい。実際にやってみる。

- 同サイトの keywords のページ から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。 大量の警告 (unknown attribute `〇〇' ignored) がコンパイラから出力されるが、コンパイルできる。 + 同サイトの keywords のページ から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。 大量の警告 (unknown attribute `〇〇' ignored) がコンパイラから出力されるが、コンパイルできる。

- 上のコードでは [[using]] をコメントアウトしているが、これは using キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。 + 上のコードでは [[using]] をコメントアウトしているが、これは using キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。

// using の例
 [[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文

- C++17 の仕様も見てみる (正確には標準化前のドラフト)。 + C++17 の仕様も見てみる (正確には標準化前のドラフト)。

@@ -155,7 +155,7 @@

- 「identifier の構文上の要件を満たすキーワードまたは代替トークンが attribute-token に含まれている場合、identifier とみなされる」とある。どうやら間違いないようだ。 + 「identifier の構文上の要件を満たすキーワードまたは代替トークンが attribute-token に含まれている場合、identifier とみなされる」とある。どうやら間違いないようだ。

@@ -189,7 +189,7 @@

- 「identifier の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。 + 「identifier の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。

diff --git a/vhosts/blog/public/posts/2021-10-02/python-unbound-local-error/index.html b/vhosts/blog/public/posts/2021-10-02/python-unbound-local-error/index.html index 3916ede3..91ec5d0a 100644 --- a/vhosts/blog/public/posts/2021-10-02/python-unbound-local-error/index.html +++ b/vhosts/blog/public/posts/2021-10-02/python-unbound-local-error/index.html @@ -66,16 +66,16 @@ NOTE

- この記事は Qiita から移植してきたものです。 元 URL: https://qiita.com/nsfisis/items/5d733703afcb35bbf399 + この記事は Qiita から移植してきたものです。元 URL: https://qiita.com/nsfisis/items/5d733703afcb35bbf399

- 本記事は Python 3.7.6 の動作結果を元にして書かれている。 + 本記事は Python 3.7.6 の動作結果を元にして書かれている。

- Python でクロージャを作ろうと、次のようなコードを書いた。 + Python でクロージャを作ろうと、次のようなコードを書いた。

def f():
@@ -87,7 +87,7 @@
 f()

- 関数 g から 関数 f のスコープ内で定義された変数 x を参照し、それに 1 を足そうとしている。 これを実行すると x += 1 の箇所でエラーが発生する。 + 関数 g から 関数 f のスコープ内で定義された変数 x を参照し、それに 1 を足そうとしている。 これを実行すると x += 1 の箇所でエラーが発生する。

@@ -97,7 +97,7 @@ f()

- local変数 x が代入前に参照された、とある。これは、fx を参照するのではなく、新しく別の変数を g 内に作ってしまっているため。 前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。var を変数宣言のための構文として擬似的に利用している。 + local変数 x が代入前に参照された、とある。これは、fx を参照するのではなく、新しく別の変数を g 内に作ってしまっているため。前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。var を変数宣言のための構文として擬似的に利用している。

# 注: var は正しい Python の文法ではない。上記参照のこと
@@ -112,7 +112,7 @@ f()
g()

- 当初の意図を表現するには、次のように書けばよい。 + 当初の意図を表現するには、次のように書けばよい。

def f():
@@ -123,7 +123,7 @@ f()
g()

- (*) のように、nonlocal を追加する。これにより一つ外側のスコープ (g の一つ外側 = f) で定義されている x を探しに行くようになる。 + (*) のように、nonlocal を追加する。これにより一つ外側のスコープ (g の一つ外側 = f) で定義されている x を探しに行くようになる。

diff --git a/vhosts/blog/public/posts/2021-10-02/ruby-detect-running-implementation/index.html b/vhosts/blog/public/posts/2021-10-02/ruby-detect-running-implementation/index.html index 6d96057f..0e9ee932 100644 --- a/vhosts/blog/public/posts/2021-10-02/ruby-detect-running-implementation/index.html +++ b/vhosts/blog/public/posts/2021-10-02/ruby-detect-running-implementation/index.html @@ -63,16 +63,16 @@ NOTE
- この記事は Qiita から移植してきたものです。 元 URL: https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791 + この記事は Qiita から移植してきたものです。元 URL: https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791

- Ruby という言語には複数の実装があるが、それらをスクリプト上からどのようにして programmatically に見分ければよいだろうか。 + Ruby という言語には複数の実装があるが、それらをスクリプト上からどのようにして programmatically に見分ければよいだろうか。

- Object クラスに定義されている RUBY_ENGINE という定数がこの用途に使える。 + Object クラスに定義されている RUBY_ENGINE という定数がこの用途に使える。

@@ -91,7 +91,7 @@ jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] "jruby"

- それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。 + それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。

@@ -197,11 +197,11 @@ jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]

- なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も 'ruby' が返ってくることを確認済み。 + なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も 'ruby' が返ってくることを確認済み。

- この表にない主要な処理系として、mruby'mruby' を返す。 + この表にない主要な処理系として、mruby'mruby' を返す。

diff --git a/vhosts/blog/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html b/vhosts/blog/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html index 9306eab1..a11a2f15 100644 --- a/vhosts/blog/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html +++ b/vhosts/blog/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html @@ -66,14 +66,14 @@ NOTE

- この記事は Qiita から移植してきたものです。 元 URL: https://qiita.com/nsfisis/items/787a8cf888a304497223 + この記事は Qiita から移植してきたものです。元 URL: https://qiita.com/nsfisis/items/787a8cf888a304497223

TL; DR

- case - in によるパターンマッチング構文でも、case - when と同じように then が使える (場合によっては使う必要がある)。 + case - in によるパターンマッチング構文でも、case - when と同じように then が使える (場合によっては使う必要がある)。

@@ -90,7 +90,7 @@ end

- このキーワードが現れうる場所はいくつかあり、ifunlessrescuecase 構文がそれに当たる。 上記のように、何か条件を書いた後 then を置き、式がそこで終了していることを示すマーカーとして機能する。 + このキーワードが現れうる場所はいくつかあり、ifunlessrescuecase 構文がそれに当たる。 上記のように、何か条件を書いた後 then を置き、式がそこで終了していることを示すマーカーとして機能する。

# Example:
@@ -118,13 +118,13 @@
           

なぜ普段は書かなくてもよいのか

- 普通 Ruby のコードで then を書くことはない。なぜか。次のコードを実行してみるとわかる。 + 普通 Ruby のコードで then を書くことはない。なぜか。次のコードを実行してみるとわかる。

if true puts 'Hello, World!' end

- 次のような構文エラーが出力される。 + 次のような構文エラーが出力される。

20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n'
@@ -134,18 +134,18 @@ if true puts 'Hello, World!' end
 ...f true puts 'Hello, World!' end

- 二つ目のメッセージは無視して一つ目を読むと、then; か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。 + 二つ目のメッセージは無視して一つ目を読むと、then; か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。

- ポイントは改行が then (や ;) の代わりとなることである。true の後に改行を入れてみる。 + ポイントは改行が then (や ;) の代わりとなることである。true の後に改行を入れてみる。

if true
 puts 'Hello, World!' end

- 無事 Hello, World! と出力されるようになった。 + 無事 Hello, World! と出力されるようになった。

@@ -158,7 +158,7 @@ puts 'Hello, World!' if a b end

- then; も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。 この例は二通りに解釈できる。 + then; も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。この例は二通りに解釈できる。

# a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価
@@ -172,18 +172,18 @@ b
 end

- then 等はこの曖昧性を排除するためにあり、条件式は if から then 等までの間にある、ということを明確にする。 C系の if 後に来る (/) や、Python の :、Rust/Go/Swift などの { も同じ役割を持つ。 + then 等はこの曖昧性を排除するためにあり、条件式は if から then 等までの間にある、ということを明確にする。 C系の if 後に来る (/) や、Python の :、Rust/Go/Swift などの { も同じ役割を持つ。

- Ruby の場合、プログラマーが書きやすいよう改行でもって then が代用できるので、ほとんどの場合 then は必要ない。 + Ruby の場合、プログラマーが書きやすいよう改行でもって then が代用できるので、ほとんどの場合 then は必要ない。

case - in における then

- ようやく本題にたどり着いた。来る Ruby 3.0 では casein キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして then 等が必要になる。 (現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。 + ようやく本題にたどり着いた。来る Ruby 3.0 では casein キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして then 等が必要になる。 (現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。

@@ -225,7 +225,7 @@ p_cases ;

- ここで、keyword_in は文字通り inp_top_expr はいわゆるパターン、thenthen キーワードのことではなく、この記事で then 等と呼んでいるもの、つまり then キーワード、;、改行のいずれかである。 + ここで、keyword_in は文字通り inp_top_expr はいわゆるパターン、thenthen キーワードのことではなく、この記事で then 等と呼んでいるもの、つまり then キーワード、;、改行のいずれかである。

@@ -254,7 +254,7 @@ p_cases end

- ところで、p_top_expr には if による guard clause が書けるので、その場合は if - then と似たような見た目になる。 + ところで、p_top_expr には if による guard clause が書けるので、その場合は if - then と似たような見た目になる。

case x
diff --git a/vhosts/blog/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html b/vhosts/blog/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html
index 6f629c69..69cfb8a4 100644
--- a/vhosts/blog/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html
+++ b/vhosts/blog/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html
@@ -63,14 +63,14 @@
               NOTE
             
             
- この記事は Qiita から移植してきたものです。 元 URL: https://qiita.com/nsfisis/items/9a429432258bbcd6c565 + この記事は Qiita から移植してきたものです。元 URL: https://qiita.com/nsfisis/items/9a429432258bbcd6c565

前置き

- Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。 + Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。

#![allow(non_camel_case_types)]
@@ -95,7 +95,7 @@
 struct str;

- では、普段単に bool と書いたとき、この bool は一体どこから来ているのか。rustc のソースを追ってみた。 + では、普段単に bool と書いたとき、この bool は一体どこから来ているのか。rustc のソースを追ってみた。

@@ -116,15 +116,15 @@

- どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。 + どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。

- 大雑把な構造としては、compiler フォルダ以下に rustc_* という名前のクレートが数十個入っている。これがどうやら rustc コマンドの実装部のようだ。 + 大雑把な構造としては、compiler フォルダ以下に rustc_* という名前のクレートが数十個入っている。これがどうやら rustc コマンドの実装部のようだ。

- rustc はセルフホストされている (= rustc 自身が Rust で書かれている) ので、boolchar などで適当に検索をかけてもノイズが多すぎて話にならない。 しかし、お誂え向きなことに i128/u128 というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って git grep してみる。 + rustc はセルフホストされている (= rustc 自身が Rust で書かれている) ので、boolchar などで適当に検索をかけてもノイズが多すぎて話にならない。しかし、お誂え向きなことに i128/u128 というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って git grep してみる。

$ git grep "\bi128\b" | wc      # i128
@@ -137,7 +137,7 @@ $ git grep "\bbool\b" | wc      # cf. bool の結果
 3563   23577  294659

- 165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。 + 165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。

$ git grep "\bi128\b"
@@ -146,7 +146,7 @@ rustc_resolve/src/lib.rs:        table.insert(sym::i128, Int(IntTy::I128));
 ...

- rustc_resolve というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。 + rustc_resolve というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。

/// Interns the names of the primitive types.
@@ -183,7 +183,7 @@ rustc_resolve/src/lib.rs:        table.insert(sym::i128, Int(IntTy::I128));
 }

- これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、 + これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、

@@ -193,7 +193,7 @@ rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));

- とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。 + とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。

/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
@@ -219,19 +219,19 @@ rustc_resolve/src/lib.rs:        table.insert(sym::i128, Int(IntTy::I128));
 }

- 関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。 if ns == TypeNS のブロック内では、primitive_type_table (上記の PrimitiveTypeTable::new() で作られた変数) に含まれている識別子 (booli32 など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。 + 関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。if ns == TypeNS のブロック内では、primitive_type_table (上記の PrimitiveTypeTable::new() で作られた変数) に含まれている識別子 (booli32 など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。

- なお、ns は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この if は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。 + なお、ns は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この if は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。

- 重要なのは、これが resolve_ident_in_lexical_scope() の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。 + 重要なのは、これが resolve_ident_in_lexical_scope() の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。

- 動作がわかったところで、例として次のコードを考える。 + 動作がわかったところで、例として次のコードを考える。

#![allow(non_camel_case_types)]
@@ -243,14 +243,14 @@ rustc_resolve/src/lib.rs:        table.insert(sym::i128, Int(IntTy::I128));
 }

- ここで main()boolstruct bool として解決される。なぜなら、プリミティブ型の判定をする前に bool という名前の別の型が見つかるからだ。 + ここで main()boolstruct bool として解決される。なぜなら、プリミティブ型の判定をする前に bool という名前の別の型が見つかるからだ。

まとめ

- Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。 + Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。

diff --git a/vhosts/blog/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html b/vhosts/blog/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html index 01684137..72c04ee1 100644 --- a/vhosts/blog/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html +++ b/vhosts/blog/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html @@ -63,21 +63,21 @@ NOTE
- この記事は Qiita から移植してきたものです。 元 URL: https://qiita.com/nsfisis/items/79ab4db8564032de0b25 + この記事は Qiita から移植してきたものです。元 URL: https://qiita.com/nsfisis/items/79ab4db8564032de0b25

TL; DR

- 違いはない。ただのエイリアス。 + 違いはない。ただのエイリアス。

調査記録

- Vim の autocmd events には似通った名前のものがいくつかある。大抵は :help に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。 + Vim の autocmd events には似通った名前のものがいくつかある。大抵は :help に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。

    @@ -105,7 +105,7 @@

    - とあり、おそらくは BufAdd のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため vim と neovim のソースコードを調査した。 + とあり、おそらくは BufAdd のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため vim と neovim のソースコードを調査した。

    @@ -117,7 +117,7 @@

    vim のソースコード

    - 以下は、autocmd events の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。 + 以下は、autocmd events の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。

    @@ -147,7 +147,7 @@

    neovim のソースコード

    - neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua で書かれている。以下にある通り、はっきり aliases と書かれている。 + neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua で書かれている。以下にある通り、はっきり aliases と書かれている。

    @@ -162,7 +162,7 @@ FileEncoding = 'EncodingChanged', },

- ところで、上では取り上げなかった FileEncoding だが、これは :help FileEncoding にしっかりと書いてある。 + ところで、上では取り上げなかった FileEncoding だが、これは :help FileEncoding にしっかりと書いてある。

                                                              *FileEncoding*
@@ -174,7 +174,7 @@ FileEncoding                    Obsolete.  It still works and is equivalent
           

まとめ

- 記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。 + 記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。

    @@ -216,7 +216,7 @@ FileEncoding Obsolete. It still works and is equivalent

- ところでこの調査で知ったのだが、BufReadBufWrite は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら Pre/Post 付きのものを使った方が分かりやすいだろう。 + ところでこの調査で知ったのだが、BufReadBufWrite は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら Pre/Post 付きのものを使った方が分かりやすいだろう。

diff --git a/vhosts/blog/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html b/vhosts/blog/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html index c501bbde..00a6265b 100644 --- a/vhosts/blog/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html +++ b/vhosts/blog/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html @@ -63,7 +63,7 @@ NOTE
- この記事は Qiita から移植してきたものです。 元 URL: https://qiita.com/nsfisis/items/4fefb361d9a693803520 + この記事は Qiita から移植してきたものです。元 URL: https://qiita.com/nsfisis/items/4fefb361d9a693803520
@@ -94,7 +94,7 @@ command! -bar -range=%

tac / tail

- tactail -r などの外部コマンドを ! を使って呼び出し、置き換える。 + tactail -r などの外部コマンドを ! を使って呼び出し、置き換える。

@@ -115,7 +115,7 @@ command! -bar -range=%

- :global コマンドは :[range]global/{pattern}/[command] のように使い、[range] で指定された範囲の行のうち、{pattern} で指定された検索パターンにマッチする行に対して、順番に [command] で指定された Ex コマンドを呼び出す。 + :global コマンドは :[range]global/{pattern}/[command] のように使い、[range] で指定された範囲の行のうち、{pattern} で指定された検索パターンにマッチする行に対して、順番に [command] で指定された Ex コマンドを呼び出す。

@@ -125,7 +125,7 @@ command! -bar -range=%

- :move コマンドは [range]:move {address} のように使い、[range] で指定された範囲の行を {address} で指定された位置に移動させる。 + :move コマンドは [range]:move {address} のように使い、[range] で指定された範囲の行を {address} で指定された位置に移動させる。

@@ -135,11 +135,11 @@ command! -bar -range=%

- :g/^/m0 のように組み合わせると、「すべての行を1行ずつ 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。 + :g/^/m0 のように組み合わせると、「すべての行を1行ずつ 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。

- なお、:g/^/m0 は全ての行を入れ替えるが、:N,Mg/^/mN-1 とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。 + なお、:g/^/m0 は全ての行を入れ替えるが、:N,Mg/^/mN-1 とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。

command! -bar -range=%
@@ -147,7 +147,7 @@ command! -bar -range=%
     \ <line1>,<line2>g/^/m<line1>-1

- これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。 + これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。

@@ -155,7 +155,7 @@ command! -bar -range=%

:g/^/m0 の問題点

- :global コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。^ は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。'hlsearch' オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと n コマンドなどの際に不便である。 + :global コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。^ は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。'hlsearch' オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと n コマンドなどの際に不便である。

@@ -186,15 +186,15 @@ command! -bar -range=% \ call <SID>reverse_lines(<line1>, <line2>)

- 実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。 + 実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。

- この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが ^ で上書きされることがなくなる。 + この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが ^ で上書きされることがなくなる。

- Vim のヘルプから該当箇所を引用する (強調は筆者による)。 + Vim のヘルプから該当箇所を引用する (強調は筆者による)。

@@ -208,7 +208,7 @@ command! -bar -range=%

- これは autocommand の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは :nohlsearch のヘルプにある。同じく該当箇所を引用する (強調は筆者による)。 + これは autocommand の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは :nohlsearch のヘルプにある。同じく該当箇所を引用する (強調は筆者による)。

@@ -222,7 +222,7 @@ command! -bar -range=%

- この仕様により、:g/^/m0 の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。 + この仕様により、:g/^/m0 の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。

@@ -239,7 +239,7 @@ command! -bar -range=% \ keeppatterns <line1>,<line2>g/^/m<line1>-1

- まさにこのための Exコマンド、:keeppatterns が存在する。:keeppatterns {command} のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。 + まさにこのための Exコマンド、:keeppatterns が存在する。:keeppatterns {command} のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。

diff --git a/vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html b/vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html index c8eed57d..b4875558 100644 --- a/vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html +++ b/vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html @@ -70,7 +70,7 @@

はじめに

- 本日開始された PHPerKaigi 2022 の PHPer チャレンジにおいて、弊社 デジタルサーカス株式会社 の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。 + 本日開始された PHPerKaigi 2022 の PHPer チャレンジにおいて、弊社 デジタルサーカス株式会社 の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。

@@ -81,7 +81,7 @@

第1問 brainf_ck.php

- ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。 + ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。

<?php
@@ -155,7 +155,7 @@ $🐘([
 ]);

- この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。 + この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。

@@ -163,14 +163,14 @@ $🐘([

絵文字

- まず目につくのは大量の絵文字だろう。 PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。 + まず目につくのは大量の絵文字だろう。 PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。

プログラム全体

- Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。 + Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。

@@ -178,7 +178,7 @@ $🐘([

- なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。 + なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。

+ + + + + + + + + +
@@ -209,7 +209,7 @@ $🐘([
                 

- それぞれの絵文字で表された関数が、各命令に対応している。 + それぞれの絵文字で表された関数が、各命令に対応している。

    @@ -243,45 +243,45 @@ $🐘([

- , (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。 + , (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。

- なお、$🐘 はいわゆる main 関数であり、プログラムの実行部分である。 + なお、$🐘 はいわゆる main 関数であり、プログラムの実行部分である。

絵文字の選択

- おおよそ意味に合致するよう選んでいるが、$🤡$🎪 は弊社デジタルサーカスにちなんでいる。 また、$🐘 は PHP のマスコットの象に由来する。 + おおよそ意味に合致するよう選んでいるが、$🤡$🎪 は弊社デジタルサーカスにちなんでいる。 また、$🐘 は PHP のマスコットの象に由来する。

strict_types

- declare 文の strict_types に指定できるのは、01 の数値リテラルだが、 0x00b1 のような値も受け付ける。 今回は、PHP 8.1 から追加された、0O または 0o から始まる八進数リテラルを使った。 + declare 文の strict_types に指定できるのは、01 の数値リテラルだが、 0x00b1 のような値も受け付ける。 今回は、PHP 8.1 から追加された、0O または 0o から始まる八進数リテラルを使った。

URL

- ソースコードのライセンスを示したこの部分だが、 + ソースコードのライセンスを示したこの部分だが、

https://creativecommons.org/publicdomain/zero/1.0/

- 完全に合法な PHP のコードである。 https: 部分はラベル、// 以降は行コメントになっている。 + 完全に合法な PHP のコードである。 https: 部分はラベル、// 以降は行コメントになっている。

リテラルなしで数値を生成する

- ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 PHP では、型変換を利用することで任意の整数を作り出すことができる。 + ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。PHP では、型変換を利用することで任意の整数を作り出すことができる。

assert(0 === +!![]);
@@ -291,33 +291,33 @@ $🐘([
 assert(10 === +(![].+!![]));

- []! を適用すると true が返ってくる。それに + を適用すると、bool から int ヘの型変換が走り、1 が生成される。10 はさらにトリッキーだ。まず 10 を作り、. で文字列として結合する ('10')。これに + を適用すると、string から int への型変換が走り、10 が生まれる (コード量に頓着しないなら、1 を 10 個足し合わせてももちろん 10 が作れる)。 + []! を適用すると true が返ってくる。それに + を適用すると、bool から int ヘの型変換が走り、1 が生成される。10 はさらにトリッキーだ。まず 10 を作り、. で文字列として結合する ('10')。これに + を適用すると、string から int への型変換が走り、10 が生まれる (コード量に頓着しないなら、1 を 10 個足し合わせてももちろん 10 が作れる)。

- また、error_reporting に指定しているのは -1 である。 これは、! によって文字列を false にし、+ によって false0 にし、さらにビット反転して -1 にしている。 + また、error_reporting に指定しているのは -1 である。 これは、! によって文字列を false にし、+ によって false0 にし、さらにビット反転して -1 にしている。

if 文なしで条件分岐

- 三項演算子ないし match 式を使うことで、if を一切書かずに条件分岐ができる。 また、&& / || も使えることがある。 遅延評価が不要なケースでは、[$t, $f][$cond] のような形で分岐することもできる。 + 三項演算子ないし match 式を使うことで、if を一切書かずに条件分岐ができる。 また、&& / || も使えることがある。遅延評価が不要なケースでは、[$t, $f][$cond] のような形で分岐することもできる。

whilefor 文なしでループ

- 不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。 ここでは、一般に Z コンビネータとして知られるものを使った ($z)。 + 不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。 ここでは、一般に Z コンビネータとして知られるものを使った ($z)。

- 実際のところ、$🤡$🎪$🐘 は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。 + 実際のところ、$🤡$🎪$🐘 は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。

- なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、 あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。 + なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、 あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。

@@ -326,7 +326,7 @@ $🐘([

第2問 riddle.php

- ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。 + ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。

<?php
@@ -365,17 +365,17 @@ $🐘([
 }

- さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 トークンを得るためには、ソースコードを読み、定数 N を特定する必要がある。 + さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。トークンを得るためには、ソースコードを読み、定数 N を特定する必要がある。

- ここでは、私の想定解を解説する。 + ここでは、私の想定解を解説する。

読解

- まずはソースコードを読んでいく。 + まずはソースコードを読んでいく。

$token = [
@@ -383,38 +383,38 @@ $🐘([
 ];

- 数値からなる $token があり、各要素をループしている。 + 数値からなる $token があり、各要素をループしている。

$x = $x ^ N;

- まずは排他的論理和 (xor) を取り、 + まずは排他的論理和 (xor) を取り、

$x = sprintf('%025b', $x);

- 二進数に変換して、 + 二進数に変換して、

$x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);

- 0 を空白に、1 を # にし、 + 0 を空白に、1 を # にし、

$x = implode("\n", str_split($x, length: 5));

- 5文字ごとに区切ったあと、改行で結合している。 + 5文字ごとに区切ったあと、改行で結合している。

ヒント

- 次に、ソースコードに書いてあるヒントを読んでいく。 + 次に、ソースコードに書いてあるヒントを読んでいく。

    @@ -436,14 +436,14 @@ $🐘([

- ここで、PHPer トークンは必ず # 記号から始まることを思いだすと、 $token の最初の数字 0x14B499C は、変換の結果 # になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。 + ここで、PHPer トークンは必ず # 記号から始まることを思いだすと、$token の最初の数字 0x14B499C は、変換の結果 # になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。

解く

- ここまでわかれば、あと一歩で解ける。すなわち、0x14B499C# に変換されるような N を見つければよい。 + ここまでわかれば、あと一歩で解ける。すなわち、0x14B499C# に変換されるような N を見つければよい。

@@ -453,7 +453,7 @@ $🐘([

assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);

- なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。 + なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。

<?php
@@ -474,7 +474,7 @@ $🐘([
 " # # ");

- この一連の変換に対する逆変換を考えると、次のようになる。 + この一連の変換に対する逆変換を考えると、次のようになる。

<?php
@@ -495,7 +495,7 @@ $🐘([
 echo "N = $n\n";

- これを実行すると、N が得られる。 + これを実行すると、N が得られる。

@@ -503,7 +503,7 @@ $🐘([

第3問 toquine.php

- ソースコードはこちら。 + ソースコードはこちら。

<?php
@@ -537,13 +537,13 @@ $t .= implode("\n", str_split(str_replace(['printf($s, $t, str_rot13("<<<'D'\n{$s}\nD"), implode(",\n", $ws));

- コメントにもあるとおり、次のようにして実行すれば答えがでてくる。 + コメントにもあるとおり、次のようにして実行すれば答えがでてくる。

$ php toquine.php | php | php | php | ...

- 実際にはもう少しパイプで繋げなければならない。 + 実際にはもう少しパイプで繋げなければならない。

@@ -551,36 +551,36 @@ $t .= implode("\n", str_split(str_replace(['

プログラム全体

- コメントにもあるとおり、これは quine (風) のプログラムになっている。 Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。 + コメントにもあるとおり、これは quine (風) のプログラムになっている。Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。

- このプログラムは、実行すると自身とほとんど同じプログラムを出力する。 異なるのはトークンになっている部分のみである。 + このプログラムは、実行すると自身とほとんど同じプログラムを出力する。異なるのはトークンになっている部分のみである。

トークン

- $xs がトークンに対応している。変換のロジックは riddle.php とほぼ同じなので省略する。 + $xs がトークンに対応している。変換のロジックは riddle.php とほぼ同じなので省略する。

状態保持

- トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。 このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、__LINE__ から情報を取得している。 + トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、__LINE__ から情報を取得している。

ROT 13

- Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。 これがあまり美しくないので、toquine.php では、ROT 13 変換を使って難読化した。 + Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。これがあまり美しくないので、toquine.php では、ROT 13 変換を使って難読化した。

- それにしてもなぜこんなものが標準ライブラリに……。 + それにしてもなぜこんなものが標準ライブラリに……。

@@ -589,15 +589,15 @@ $t .= implode("\n", str_split(str_replace(['

おわりに

- 解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。 + 解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。

- 今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、 来年は 5問、より面白い問題を持っていきます。 + 今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、来年は 5問、より面白い問題を持っていきます。

- 実はもう作りはじめているので、どうか来年もありますように……。 + 実はもう作りはじめているので、どうか来年もありますように……。

diff --git a/vhosts/blog/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html b/vhosts/blog/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html index 9eb5685d..d3d21364 100644 --- a/vhosts/blog/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html +++ b/vhosts/blog/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html @@ -58,7 +58,7 @@

はじめに

- こんなものを作った。 + こんなものを作った。

$ term-banner 'Hello, World!' 'こんにちは、' '世界!'
@@ -67,7 +67,7 @@

- コマンドライン引数として渡した文字列をターミナルに大きく表示する。 + コマンドライン引数として渡した文字列をターミナルに大きく表示する。

@@ -78,30 +78,30 @@

Motivation

- 以前、big-clock-mode という似たようなプログラムを書いた。 これは tmux の :clock-mode コマンドに着想を得たもので、:clock-mode よりも大きく現在時刻を表示する。 + 以前、big-clock-mode という似たようなプログラムを書いた。 これは tmux の :clock-mode コマンドに着想を得たもので、:clock-mode よりも大きく現在時刻を表示する。

- big-clock-mode を開発したのは、次のようなシチュエーションで使うためである。 弊社では現在リモートワークが基本だが、web 会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。 こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。 + big-clock-mode を開発したのは、次のようなシチュエーションで使うためである。弊社では現在リモートワークが基本だが、web 会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。

- それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。 + それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。

- しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。 どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。 + しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。

- そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。 まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。 + そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。

プログラム

- 全体の流れは次のようになっている。 + 全体の流れは次のようになっている。

    @@ -119,38 +119,38 @@

- big-clock-mode が Go 製なので、今回も Go で書いた。 PNG が標準ライブラリにあったり、Shift-JIS のエンコーディングが準標準ライブラリにあったりしたのは助かった。 + big-clock-mode が Go 製なので、今回も Go で書いた。 PNG が標準ライブラリにあったり、Shift-JIS のエンコーディングが準標準ライブラリにあったりしたのは助かった。

- フォントファイルは go:embed で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。 仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。 + フォントファイルは go:embed で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。

フォント

- フリーの 8x8 ビットマップフォントである、美咲フォント 2021-05-05a 版 を使わせていただいた。 + フリーの 8x8 ビットマップフォントである、美咲フォント 2021-05-05a 版 を使わせていただいた。

- はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。 同じく 8x8 で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。 + はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。同じく 8x8 で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。

- 美咲フォントは、平仮名・片仮名に留まらず、JIS 第一・第二水準の漢字までサポートしている。 第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。 + 美咲フォントは、平仮名・片仮名に留まらず、JIS 第一・第二水準の漢字までサポートしている。第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。

- さらに言うと、実のところ美咲フォントは実サイズ 7x7 で作られており、余白が設けられている。 これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。 おかげでコーディングまで楽になった。 + さらに言うと、実のところ美咲フォントは実サイズ 7x7 で作られており、余白が設けられている。これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。おかげでコーディングまで楽になった。

- ゴシック体と明朝体があったが、私の好みで明朝体の方にした。 ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。 + ゴシック体と明朝体があったが、私の好みで明朝体の方にした。ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。

- 2022-04-27 追記: -f オプションで選べるようにした。 + 2022-04-27 追記: -f オプションで選べるようにした。

diff --git a/vhosts/blog/public/posts/2022-05-01/phperkaigi-2022/index.html b/vhosts/blog/public/posts/2022-05-01/phperkaigi-2022/index.html index e20bd53b..37c10d45 100644 --- a/vhosts/blog/public/posts/2022-05-01/phperkaigi-2022/index.html +++ b/vhosts/blog/public/posts/2022-05-01/phperkaigi-2022/index.html @@ -67,11 +67,11 @@

はじめに

- 2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に、 一般参加者として参加した。 弊社デジタルサーカス株式会社はダイヤモンドスポンサーとなっており、 スポンサー枠のチケットを使わせていただいた。 + 2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に、一般参加者として参加した。弊社デジタルサーカス株式会社はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。

- 昨年のレポートはこちら。 + 昨年のレポートはこちら

@@ -80,7 +80,7 @@

厳選おすすめトーク

- 多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。 是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。 + 多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。

@@ -89,11 +89,11 @@

- PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。 + PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。

- 本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。 + 本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。

@@ -107,7 +107,7 @@
これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!
- またそれらを理解した上でのエラーハンドリングを学びましょう。 + またそれらを理解した上でのエラーハンドリングを学びましょう。

@@ -123,7 +123,7 @@
サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、
- エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。 + エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。

@@ -133,7 +133,7 @@

- 昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。 + 昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。

@@ -145,7 +145,7 @@
・移植中に遭遇したトラブルとその解決策
- といった文脈や葛藤が存在しています。 + といった文脈や葛藤が存在しています。

@@ -157,7 +157,7 @@
・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう
- ことを目的とします。 + ことを目的とします。

@@ -167,15 +167,15 @@

- サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。 + サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。

- フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。 + フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。

- このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。 + このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。

@@ -183,7 +183,7 @@

トークン問題の作成

- 今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。 こちらについては別途記事にしているので、そちらを参照されたい。 + 今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。こちらについては別途記事にしているので、そちらを参照されたい。

@@ -192,36 +192,36 @@

1位になった。
- また、賞品として Echo Show 15 をいただいた。 + また、賞品として Echo Show 15 をいただいた。

カンファレンス全体への感想

- 去年の参加レポ では、こんなことを書いた。 + 去年の参加レポ では、こんなことを書いた。

- 1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、 後から見返せる発表やスライドに注力してしまった、ということだ。 発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 + 1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。
- まあ初カンファレンスだし、とお茶を濁しておこう。 + まあ初カンファレンスだし、とお茶を濁しておこう。

この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。
- これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、 質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。 + これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。

- なお、アンカンファレンスについては、1日目の終わりにトークン問題の解説放送もおこなった。 + なお、アンカンファレンスについては、1日目の終わりにトークン問題の解説放送もおこなった。

- また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。 今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。 + また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。

@@ -229,7 +229,7 @@

そして来年へ……?

- PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。 + PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。

    @@ -256,11 +256,11 @@

    - 最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。 + 最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。

    - ではまた来年。 + ではまた来年。

diff --git a/vhosts/blog/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html b/vhosts/blog/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html index 492719a2..1f7ad6ba 100644 --- a/vhosts/blog/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html +++ b/vhosts/blog/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html @@ -67,11 +67,11 @@

はじめに

- 本日 PHP カンファレンス沖縄 2022 が開催された (らしい)。 + 本日 PHP カンファレンス沖縄 2022 が開催された (らしい)。

- カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。 + カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。

    @@ -88,7 +88,7 @@

    - 細かいレギュレーションは不明だったので、勝手に定めた。 + 細かいレギュレーションは不明だったので、勝手に定めた。

      @@ -124,7 +124,7 @@
      [<?php $n=$argv[1];foreach([1e4,5e3,2e3,1e3,500,100,50,10,5,1]as$x)for(;$n>=$x;$n-=$x)$r[]=$x;echo implode(', ',$r??[]);?>]

      - しめて 123 バイトとなった (末尾改行を含めずにカウント)。 + しめて 123 バイトとなった (末尾改行を含めずにカウント)。

      @@ -147,36 +147,36 @@

      指数表記

      - 割と多くの言語のゴルフで使えるテクニック。 e を用いた指数表記で、大きな数を短く表す。 このコードでは 10000500020001000 を指数表記している。 + 割と多くの言語のゴルフで使えるテクニック。e を用いた指数表記で、大きな数を短く表す。このコードでは 10000500020001000 を指数表記している。

      foreach や for の中身を1つの文に

      - foreachforif などの後ろには、 通常 { を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、{} を省略できる。 C言語などでも使える。 + foreachforif などの後ろには、通常 { を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、{} を省略できる。C言語などでも使える。

      $r に初期値を入れない

      - PHP では、$r[] = ...... のような配列の末尾に追加する式を実行したとき、 $r が未定義だった場合は $r を勝手に定義して空の配列で初期化してくれる。 これを利用すると、$r = []; のような初期化が不要になる。 + PHP では、$r[] = ...... のような配列の末尾に追加する式を実行したとき、$r が未定義だった場合は $r を勝手に定義して空の配列で初期化してくれる。これを利用すると、$r = []; のような初期化が不要になる。

      - ただし、プログラムに 0 が渡されるとループを一度も回らないので、$r が未定義になってしまい、 implode() に渡すところでエラーになる。 それを防ぐために $r ?? [] を使っている。 + ただし、プログラムに 0 が渡されるとループを一度も回らないので、$r が未定義になってしまい、implode() に渡すところでエラーになる。それを防ぐために $r ?? [] を使っている。

      - もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。 + もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。

      PHP タグの外に文字列を置く

      - PHP では、<?php ?> で囲われた部分の外側にある文字列は、そのまま出力される。 今回のケースでは、先頭と末尾に必ず [] を出力するので、そのまま書いてやればよい。 + PHP では、<?php ?> で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず [] を出力するので、そのまま書いてやればよい。

    @@ -184,7 +184,7 @@

    おわりに

    - 最後になりましたが、めもりーさん、楽しい問題をありがとうございました。 + 最後になりましたが、めもりーさん、楽しい問題をありがとうございました。

    diff --git a/vhosts/blog/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html b/vhosts/blog/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html index 493789bb..fb44e927 100644 --- a/vhosts/blog/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html +++ b/vhosts/blog/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html @@ -59,7 +59,7 @@

    - 先日、私の勤める デジタルサーカス株式会社PHP Foundation へ $2,000 の寄付をおこないました。 + 先日、私の勤める デジタルサーカス株式会社PHP Foundation へ $2,000 の寄付をおこないました。

    @@ -67,14 +67,14 @@

    - 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。 + 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。

なぜ?

- 組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。 + 組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。

@@ -83,31 +83,31 @@

- 結局これを通したい (私の中での) 最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、 ↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、 寄付の報告が流れてきたり、OSS のフリーライドの話が流れてきたりするたびに、自尊心が毀損される、というか (これは大袈裟すぎる表現で、実際にはそこまで明確に傷ついているわけではありませんが)。 + 結局これを通したい (私の中での) 最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、寄付の報告が流れてきたり、OSS のフリーライドの話が流れてきたりするたびに、自尊心が毀損される、というか (これは大袈裟すぎる表現で、実際にはそこまで明確に傷ついているわけではありませんが)。

- 追記: 「肩身が狭くなる」というのがより適切でした。 + 追記: 「肩身が狭くなる」というのがより適切でした。

- ※文中の「↑にしても」は、ここに載せていない別の投稿を指しています。 + ※文中の「↑にしても」は、ここに載せていない別の投稿を指しています。

- OSS を金銭的に支援したり、技術カンファレンスへ協賛したり (あるいは CTO がカンファレンスを年2で主催したり: iOSDC PHPerKaigi) といった行為は、コミュニティへの貢献であると同時に、社員に対する精神的福利厚生でもあると言えるでしょう (知らんけど)。 これらは、技術や技術者を大切にする組織である、ということの、対外的にも対内的にも強力なメッセージなのです。 + OSS を金銭的に支援したり、技術カンファレンスへ協賛したり (あるいは CTO がカンファレンスを年2で主催したり: iOSDC PHPerKaigi) といった行為は、コミュニティへの貢献であると同時に、社員に対する精神的福利厚生でもあると言えるでしょう (知らんけど)。これらは、技術や技術者を大切にする組織である、ということの、対外的にも対内的にも強力なメッセージなのです。

- 以上が、私が社内で寄付の件を進めた (かなり私的な) 理由です。 + 以上が、私が社内で寄付の件を進めた (かなり私的な) 理由です。

おわりに

- 最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。 この場を借りて感謝申し上げます。 + 最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。この場を借りて感謝申し上げます。

diff --git a/vhosts/blog/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html b/vhosts/blog/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html index 1fe1b48d..ab8e1136 100644 --- a/vhosts/blog/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html +++ b/vhosts/blog/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html @@ -64,14 +64,14 @@

記事の構成について

- この記事は、普通の fizzbuzz を徐々に変形して最終形にしていく、という構成で書かれている。 最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、 このページ にソースコードがあるので、そちらを先に見てほしい。 + この記事は、普通の fizzbuzz を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、このページ にソースコードがあるので、そちらを先に見てほしい。

レギュレーション

- PHP で、次のような制約の下に fizzbuzz を書いた。 + PHP で、次のような制約の下に fizzbuzz を書いた。

    @@ -111,7 +111,7 @@

- 備考: PHP には short_open_tag というオプションがあり、 これを有効にするとファイル冒頭の <?php の代わりに <? を使うことができ、文字どおり1行2文字で書ける。 ただ、このオプションはデフォルト off になっている環境が多いようなので、今回は使わないことにした。 + 備考: PHP には short_open_tag というオプションがあり、これを有効にするとファイル冒頭の <?php の代わりに <? を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト off になっている環境が多いようなので、今回は使わないことにした。

@@ -122,7 +122,7 @@

- 特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。 + 特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。

#\
@@ -201,11 +201,11 @@ c\
 /* あとは同じように普通のプログラムを変形するだけなので省略 */

- バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。 + バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。

- さて、PHP ではそもそもバックスラッシュを行継続に使うことができない。 これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。 例えば、echo で出力することや、for でループすること、 new でインスタンスを生成することができない。 特に、出力は fizzbuzz をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。 + さて、PHP ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、echo で出力することや、for でループすること、new でインスタンスを生成することができない。特に、出力は fizzbuzz をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。

@@ -243,11 +243,11 @@ c\

- に反する (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。 + に反する (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。

- また、2文字だと文字列がまともに書けないのも辛い。'' だけで2文字使うので、 「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので + また、2文字だと文字列がまともに書けないのも辛い。'' だけで2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので

$a
@@ -256,11 +256,11 @@ a'
 ;;

- とすると $a"\na" になるのだが、余計な改行が入ってしまう。 + とすると $a"\na" になるのだが、余計な改行が入ってしまう。

- これらの障害をどのように乗り越えるのか、次節から見ていく。 + これらの障害をどのように乗り越えるのか、次節から見ていく。

@@ -269,7 +269,7 @@ a'

普通の (?) fizzbuzz

- まずは普通に書くとしよう。 + まずは普通に書くとしよう。

<?php
@@ -279,14 +279,14 @@ a'
 }

- 素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。 + 素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。

for の排除

- for は、3文字もある長いキーワードである。 こんなものは使えない。array_ 系の関数を使って、適当に置き換えるとしよう。 + for は、3文字もある長いキーワードである。こんなものは使えない。array_ 系の関数を使って、適当に置き換えるとしよう。

<?php
@@ -299,14 +299,14 @@ fn($i) =>
 );

- array_walkrangeprintf といった for よりも長いトークンが現れてしまったが、これは次節で直すことにする。 なお、echo は文 (statement) であり式 (expression) ではないので、式である printf に置き換えた。 + array_walkrangeprintf といった for よりも長いトークンが現れてしまったが、これは次節で直すことにする。なお、echo は文 (statement) であり式 (expression) ではないので、式である printf に置き換えた。

関数呼び出しの短縮

- rangearray_walkprintf は長すぎるのでどうにかせねばならない。 ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。 + rangearray_walkprintf は長すぎるのでどうにかせねばならない。ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。

<?php
@@ -323,14 +323,14 @@ fn($i) =>
 );

- これで関数を呼び出している所は短くなった。 では、$r$w$p、 また 'Fizz''Buzz' はどうやって 1 行 2 文字に収めるのか。 次のテクニックへ移ろう。 + これで関数を呼び出している所は短くなった。では、$r$w$p、また 'Fizz''Buzz' はどうやって 1 行 2 文字に収めるのか。次のテクニックへ移ろう。

余談: PHP 8.x で動作しなくてもいいなら

- 今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。 + 今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。

@@ -342,7 +342,7 @@ fn($i) =>

- というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。 例えば、 Fizz という文字列が欲しければ、次のようにする。 + というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。例えば、 Fizz という文字列が欲しければ、次のようにする。

$f
@@ -353,7 +353,7 @@ fn($i) =>
 ;;

- こうして簡単に文字列を作れる。 なお、この仕様は 7.x 時点でも警告を受けるので、@ 演算子を使って抑制してやるとよい。 + こうして簡単に文字列を作れる。なお、この仕様は 7.x 時点でも警告を受けるので、@ 演算子を使って抑制してやるとよい。

$f
@@ -367,18 +367,18 @@ F.
 ;;

- むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。 + むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。

文字列リテラルの短縮

- 実際に使った手法の説明に移る。 + 実際に使った手法の説明に移る。

- ずばり、文字列同士のビット演算を使う。 PHP では、文字列同士でビット演算 (&|^) をした場合、 文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。 + ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 (&|^) をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。

$a = "12345";
@@ -394,7 +394,7 @@ F.
 // => F]AXQ

- これを踏まえ、次のコードを見てみよう。 + これを踏まえ、次のコードを見てみよう。

$x = "x\nOm\n";
@@ -403,7 +403,7 @@ F.
 echo "$r\n";

- 実行すると、range が表示される。 さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。 書きかえてみよう。 + 実行すると、range が表示される。さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。書きかえてみよう。

$x
@@ -420,7 +420,7 @@ o'
 echo "$r\n";

- さらに # を使って適当に調整すると、次のようになる。 + さらに # を使って適当に調整すると、次のようになる。

$x
@@ -443,11 +443,11 @@ o'
 echo "$r\n";

- 1行あたり2文字で、range という文字列を生成することに成功した。 他の必要な文字列にも、同様の処理をほどこす。 + 1行あたり2文字で、range という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。

- 備考: Buzz 中にある小文字の u は、このロジックだと non-printable な文字になってしまう。 ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。 + 備考: Buzz 中にある小文字の u は、このロジックだと non-printable な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。

@@ -455,7 +455,7 @@ o'

完成系

- 完成したものがこちら。 + 完成したものがこちら。

<?php
@@ -612,18 +612,18 @@ _!
           

感想など

- PHP は、スクリプト言語の中だとシンタックスシュガーが少ない (体感)。 この挑戦は不可能に思われたが、PHP マニュアルとにらめっこしていたらなんとかなった。 + PHP は、スクリプト言語の中だとシンタックスシュガーが少ない (体感)。この挑戦は不可能に思われたが、PHP マニュアルとにらめっこしていたらなんとかなった。

- みんなもプログラムを細長くしよう。 + みんなもプログラムを細長くしよう。

余談2: 別解

- PHP では、バッククォートを使ってシェルを呼び出せる。 これは shell_exec 関数と等価である。 さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。 + PHP では、バッククォートを使ってシェルを呼び出せる。これは shell_exec 関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。

<?php
@@ -640,7 +640,7 @@ o\
 `);

- なお、ここでは簡単のため出力に printf をそのまま使っているが、 実際には printf という文字列を合成して可変関数で呼び出す。 + なお、ここでは簡単のため出力に printf をそのまま使っているが、実際には printf という文字列を合成して可変関数で呼び出す。

@@ -656,11 +656,11 @@ o\

- に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。 + に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。

- もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。 + もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。

<?php
@@ -694,7 +694,7 @@ ${
 `);

- 先程と同じく、chrprintf を生成する部分は長くなるので省いた。 + 先程と同じく、chrprintf を生成する部分は長くなるので省いた。

${
@@ -702,7 +702,7 @@ ${
 '}

- は変数で、中にはスペースとエスケープが入っている (chr(32) . chr(92))。 シェルに渡されている文字列は次のようになる。 + は変数で、中にはスペースとエスケープが入っている (chr(32) . chr(92))。シェルに渡されている文字列は次のようになる。

e\
@@ -715,15 +715,15 @@ o\
 3\

- これは、前掲したコマンドと同じだ。 かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。 Fizzbuzz のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう (試してないけど)。 + これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう (試してないけど)。

- ということでこれは別解ということにしておく。 + ということでこれは別解ということにしておく。

- ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。 + ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。

${
@@ -731,7 +731,7 @@ o\
 '}

- 最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。 + 最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。

diff --git a/vhosts/blog/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html b/vhosts/blog/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html index 611c77ed..8d72a4f2 100644 --- a/vhosts/blog/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html +++ b/vhosts/blog/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html @@ -64,7 +64,7 @@

はじめに

- 2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の、 PHPerKaigi 2023 において、 昨年と同様に、弊社 デジタルサーカス株式会社 から、 トークン問題を出題予定である。 + 2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の、PHPerKaigi 2023 において、昨年と同様に、弊社 デジタルサーカス株式会社 から、トークン問題を出題予定である。

@@ -72,18 +72,18 @@

- すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。 せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。 + すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。

- 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。 + 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。

問題

- 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 + 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。

<?php
@@ -112,39 +112,39 @@ $π = trim($π);
           

トークン入手方法

- ソースを見るとわかるとおり、$argv[1] を参照している。 それを なる変数に代入しているので、円周率を渡してみる。 + ソースを見るとわかるとおり、$argv[1] を参照している。それを なる変数に代入しているので、円周率を渡してみる。

$ php Q.php 3.14
 Failed.

- 失敗してしまった。精度を上げてみる。 + 失敗してしまった。精度を上げてみる。

$ php Q.php 3.1415
 Failed.

- だめだった。これを成功するまで繰り返す。 + だめだった。これを成功するまで繰り返す。

- 最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。 + 最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。

$ php Q.php 3.1415926535897932
 Token: #YO

- めでたくトークン「#YO」が手に入った。 + めでたくトークン「#YO」が手に入った。

解説

- 短いので頭から追っていく。 + 短いので頭から追っていく。

$π = $argv[1] ?? null;
@@ -157,17 +157,17 @@ $π = trim($π);
 }

- 入力のバリデーション部分。数値のみ受け付ける。 + 入力のバリデーション部分。数値のみ受け付ける。

$s = implode(array_map(chr(...), str_split($π, 2)));

- を 2 文字ごとに区切り (str_split)、 数値を ASCII コードと見做して文字に変換 (chr) して結合 (implode) している。 + を 2 文字ごとに区切り (str_split)、数値を ASCII コードと見做して文字に変換 (chr) して結合 (implode) している。

- 例えば、'656667' だったとすると、 656667 に対応した 'A''B''C' へと変換され、'ABC' になる。 + 例えば、'656667' だったとすると、656667 に対応した 'A''B''C' へと変換され、'ABC' になる。

$π = '656667';
@@ -179,11 +179,11 @@ $π = trim($π);
 $t = $m[1] ?? '';

- 正規表現でマッチングしている。\x23# と同じであることに留意すると、 この正規表現は「# から始まる 2 以上の長さ (含 #) の文字列で、 最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。 + 正規表現でマッチングしている。\x23# と同じであることに留意すると、この正規表現は「# から始まる 2 以上の長さ (含 #) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。

- なお、# を直接書いていないのは、/#.+?) / と書くと、 #.+?) という意図せぬトークンが登録されてしまうからである。 + なお、# を直接書いていないのは、/#.+?) / と書くと、#.+?) という意図せぬトークンが登録されてしまうからである。

if (md5($t) === '056e831a4146bf123e8ea16613303d2e') {
@@ -193,18 +193,18 @@ $π = trim($π);
 }

- 最後にトークンのハッシュ値を見て、想定解かどうかを確認する。 + 最後にトークンのハッシュ値を見て、想定解かどうかを確認する。

おわりに

- 円周率を何桁も計算して ASCII コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。 + 円周率を何桁も計算して ASCII コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。

- 最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた (ちなみに、それでも M_PIpi() では精度が足りない)。 見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。 むしろ、100 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。 + 最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた (ちなみに、それでも M_PIpi() では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。

diff --git a/vhosts/blog/public/posts/2022-10-28/setup-server-for-this-site/index.html b/vhosts/blog/public/posts/2022-10-28/setup-server-for-this-site/index.html index ddf2a5b7..e6644a58 100644 --- a/vhosts/blog/public/posts/2022-10-28/setup-server-for-this-site/index.html +++ b/vhosts/blog/public/posts/2022-10-28/setup-server-for-this-site/index.html @@ -64,18 +64,18 @@

はじめに

- これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS に移行した。 そのときにおこなったサーバのセットアップ作業を書き残しておく。 99 % 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。 + これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS に移行した。そのときにおこなったサーバのセットアップ作業を書き残しておく。99 % 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。

- 未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。 + 未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。

VPS

- さくらの VPS の 2 GB プラン。 そこまで真面目に選定していないので、困ったら移動するかも。 + さくらの VPS の 2 GB プラン。そこまで真面目に選定していないので、困ったら移動するかも。

@@ -84,28 +84,28 @@

サーバのホスト名を決める

- モチベーションが上がるという効能がある。今回は藤原定家から取って teika にした。 たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。 + モチベーションが上がるという効能がある。今回は藤原定家から取って teika にした。たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。

SSH の鍵生成

- ローカルマシンで鍵を生成する。 + ローカルマシンで鍵を生成する。

$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/teika.key
 $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key

- teika.key はローカルからサーバへの接続用、github2teika.key は、 GitHub Actions からサーバへのデプロイ用。 + teika.key はローカルからサーバへの接続用、github2teika.key は、GitHub Actions からサーバへのデプロイ用。

SSH の設定

- .ssh/config に設定しておく。 + .ssh/config に設定しておく。

Host teika
@@ -122,14 +122,14 @@ $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key

SSH 接続

- VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。 + VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。

ユーザを作成する

- 管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。 sudo グループに追加して sudo できるようにし、su で切り替え。 + 管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。sudo グループに追加して sudo できるようにし、su で切り替え。

$ sudo adduser **********
@@ -150,14 +150,14 @@ $ chmod 700 ~/.ssh
 $ vi ~/.ssh/authorized_keys

- authorized_keys には、ローカルで生成した ~/.ssh/teika.key.pub~/.ssh/github2teika.key.pub の内容をコピーする。 + authorized_keys には、ローカルで生成した ~/.ssh/teika.key.pub~/.ssh/github2teika.key.pub の内容をコピーする。

SSH の設定

- SSH の設定を変更し、少しでも安全にしておく。 + SSH の設定を変更し、少しでも安全にしておく。

$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
@@ -178,7 +178,7 @@ $ sudo vi /etc/ssh/sshd_config

- そして設定を反映。 + そして設定を反映。

$ sudo systemctl restart sshd
@@ -188,7 +188,7 @@ $ sudo systemctl status sshd

SSH で接続確認

- 今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。 セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。 + 今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。

$ ssh teika
@@ -197,7 +197,7 @@ $ sudo systemctl status sshd

ポートの遮断

- デフォルトの 22 番を閉じ、設定したポートだけ空ける。 + デフォルトの 22 番を閉じ、設定したポートだけ空ける。

$ sudo ufw deny ssh
@@ -207,27 +207,27 @@ $ sudo ufw reload
 $ sudo ufw status

- ここでもう一度 SSH の接続確認を挟む。 + ここでもう一度 SSH の接続確認を挟む。

GitHub 用の SSH 鍵

- GitHub に置いてある private リポジトリをサーバから clone したいので、SSH 鍵を生成して置いておく。 + GitHub に置いてある private リポジトリをサーバから clone したいので、SSH 鍵を生成して置いておく。

$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github.key
 $ cat ~/.ssh/github.key.pub

- GitHub の設定画面 から、この公開鍵を追加する。 + GitHub の設定画面 から、この公開鍵を追加する。

$ vi ~/.ssh/config

- 設定はこう。 + 設定はこう。

Host github.com
@@ -238,7 +238,7 @@ $ cat ~/.ssh/github.key.pub
IdentitiesOnly yes

- 最後に接続できるか確認しておく。 + 最後に接続できるか確認しておく。

$ ssh -T github.com
@@ -259,7 +259,7 @@ $ sudo apt autoremove

DNS に IP アドレスを登録する

- このサーバは固定の IP アドレスがあるので、A レコードに直接入れるだけで済んだ。 + このサーバは固定の IP アドレスがあるので、A レコードに直接入れるだけで済んだ。

@@ -276,7 +276,7 @@ $ sudo apt autoremove

HTTP/HTTPS を通す

- 80 番と 443 番を空ける。 + 80 番と 443 番を空ける。

$ sudo ufw allow 80/tcp
@@ -308,7 +308,7 @@ $ make setup

感想

- (業務でなく) 個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。 とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。 コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。 次の式年遷宮では、手順の一部だけでも自動化したいところ。 + (業務でなく) 個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。

diff --git a/vhosts/blog/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html b/vhosts/blog/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html index bf288a77..147d7a81 100644 --- a/vhosts/blog/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html +++ b/vhosts/blog/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html @@ -64,7 +64,7 @@

はじめに

- 2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の PHPerKaigi 2023 において、 昨年と同様に、弊社 デジタルサーカス株式会社 からトークン問題を出題予定である。 + 2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の PHPerKaigi 2023 において、昨年と同様に、弊社 デジタルサーカス株式会社 からトークン問題を出題予定である。

@@ -72,11 +72,11 @@

- すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。 + すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。

- 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。 + 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。

@@ -87,7 +87,7 @@

問題

- 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 + 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。

<?php printf((isset($s)?fn($s)=>trim($s,"​"):fn($s)=>chr(strlen($s)/3))($s='​<?php printf((isset($s)?fn($s)=>trim($s,"​"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
@@ -102,14 +102,14 @@
 <?php printf((isset($s)?fn($s)=>trim($s,"​"):fn($s)=>chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​<?php printf((isset($s)?fn($s)=>trim($s,"​"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>

- "And Then There Were None" (そして誰もいなくなった) と名付けた作品。変則 quine (自分自身と同じソースコードを出力するプログラム) になっている。 + "And Then There Were None" (そして誰もいなくなった) と名付けた作品。変則 quine (自分自身と同じソースコードを出力するプログラム) になっている。

トークン入手方法

- 実行してみると、次のような出力が得られる。 + 実行してみると、次のような出力が得られる。

#
@@ -124,7 +124,7 @@
 <?php printf((isset($s)?fn($s)=>trim($s,"​"):fn($s)=>chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​<?php printf((isset($s)?fn($s)=>trim($s,"​"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>

- 1 行目を除き、先ほどのコードとほぼ同じものが出てきた。もう一度実行してみる。 + 1 行目を除き、先ほどのコードとほぼ同じものが出てきた。もう一度実行してみる。

#
@@ -139,7 +139,7 @@ W
 <?php printf((isset($s)?fn($s)=>trim($s,"​"):fn($s)=>chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​<?php printf((isset($s)?fn($s)=>trim($s,"​"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>

- 今度は 2 行目が書き換えられた。すべての行が変化するまで繰り返すと次のようになる。 + 今度は 2 行目が書き換えられた。すべての行が変化するまで繰り返すと次のようになる。

#
@@ -154,24 +154,24 @@ H
 P

- トークン「#WELOVEPHP」が手に入った。 + トークン「#WELOVEPHP」が手に入った。

解説

- 一見すると同じ行が 10 行並んでいるだけなのにも関わらず、なぜそれぞれの行で出力が変わるのか。ソースコードをコピーして、適当なエディタに貼り付けるとわかりやすい。 + 一見すると同じ行が 10 行並んでいるだけなのにも関わらず、なぜそれぞれの行で出力が変わるのか。ソースコードをコピーして、適当なエディタに貼り付けるとわかりやすい。

- Vim で開くと次のようになる (1 行目を抜粋)。 + Vim で開くと次のようになる (1 行目を抜粋)。

<?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>

- <200b> と表示されているのは、Unicode の U+200b で、ゼロ幅スペースである。 + <200b> と表示されているのは、Unicode の U+200b で、ゼロ幅スペースである。

@@ -180,44 +180,44 @@ P

- エディタによっては、ゼロ幅スペースが見えないことがある。VSCode ではブラウザと同様に不可視だった。 + エディタによっては、ゼロ幅スペースが見えないことがある。VSCode ではブラウザと同様に不可視だった。

- 文字列リテラルの中にゼロ幅スペースを仕込むことで、見た目を変えずに情報をエンコードすることが可能となる。 + 文字列リテラルの中にゼロ幅スペースを仕込むことで、見た目を変えずに情報をエンコードすることが可能となる。

- 続いて、トークンへの変換ロジックを解析する。注目すべきはこの部分だ。以下、ゼロ幅スペースは Vim での表示に合わせて <200b> と記載する。 + 続いて、トークンへの変換ロジックを解析する。注目すべきはこの部分だ。以下、ゼロ幅スペースは Vim での表示に合わせて <200b> と記載する。

fn($s)=>chr(strlen($s)/3)

- PHP の strlen() は文字列のバイト数を返す。1 行目の $s は以下の内容となっており、 + PHP の strlen() は文字列のバイト数を返す。1 行目の $s は以下の内容となっており、

$s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'

- このソースコードは UTF-8 で書かれているので、105 バイトになる。それを 3 で割ると 35 となり、これは # の ASCII コードと一致する。他の行も、同様にしてゼロ幅スペースを詰めることで文字列長を調整し、トークンをエンコードしている。 + このソースコードは UTF-8 で書かれているので、105 バイトになる。それを 3 で割ると 35 となり、これは # の ASCII コードと一致する。他の行も、同様にしてゼロ幅スペースを詰めることで文字列長を調整し、トークンをエンコードしている。

- デコード部以外の部分は、quine のための記述である。 + デコード部以外の部分は、quine のための記述である。

おわりに

- CVE-2021-42574 に着想を得た作品。この脆弱性は、Unicode の制御文字である left-to-right mark と right-to-left mark を利用し、ソースコードの実際の内容を欺く、というもの。簡単のためゼロ幅スペースを用いることとし、ついでに quine にもするとこうなった。 + CVE-2021-42574 に着想を得た作品。この脆弱性は、Unicode の制御文字である left-to-right mark と right-to-left mark を利用し、ソースコードの実際の内容を欺く、というもの。簡単のためゼロ幅スペースを用いることとし、ついでに quine にもするとこうなった。

- ボツになった理由は、ゼロ幅スペースを表示してくるエディタが想像以上に多かったため。「同じ行が並んでいるだけなのに出力が異なる」というアイデアの根幹を崩されてしまうので、この問題は不採用となった。 + ボツになった理由は、ゼロ幅スペースを表示してくるエディタが想像以上に多かったため。「同じ行が並んでいるだけなのに出力が異なる」というアイデアの根幹を崩されてしまうので、この問題は不採用となった。

diff --git a/vhosts/blog/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html b/vhosts/blog/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html index dd0a5d39..38e6a3f6 100644 --- a/vhosts/blog/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html +++ b/vhosts/blog/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html @@ -64,7 +64,7 @@

はじめに

- 2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の PHPerKaigi 2023 において、 昨年と同様に、弊社 デジタルサーカス株式会社 からトークン問題を出題予定である。 + 2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の PHPerKaigi 2023 において、昨年と同様に、弊社 デジタルサーカス株式会社 からトークン問題を出題予定である。

@@ -72,11 +72,11 @@

- すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。 せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。 + すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。

- 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ → 忘れていたので 12 月公開予定だった記事を今書いている)。 + 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ → 忘れていたので 12 月公開予定だった記事を今書いている)。

    @@ -93,7 +93,7 @@

    問題

    - 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 + 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。

    <?php
    @@ -210,11 +210,11 @@
     }

    - "Catchline" と名付けた作品。実行するとトークン #base64_decode('SGVsbG8sIFdvcmxkIQ==') が得られる。 + "Catchline" と名付けた作品。実行するとトークン #base64_decode('SGVsbG8sIFdvcmxkIQ==') が得られる。

    - トークンは PHP の式になっていて、評価すると Hello, World! という文字列になる。PHPer チャレンジのトークンには空白を含められないという制約があるが、こういった形でトークンにすれば回避できる。 + トークンは PHP の式になっていて、評価すると Hello, World! という文字列になる。PHPer チャレンジのトークンには空白を含められないという制約があるが、こういった形でトークンにすれば回避できる。

    @@ -223,7 +223,7 @@

    概要

    - 例外が発生した行数にデータをエンコードし、それを catch で捕まえて表示している。 + 例外が発生した行数にデータをエンコードし、それを catch で捕まえて表示している。

    @@ -244,7 +244,7 @@

- このうち 1つ目のケースは、 finally 節の中でエラーを投げると PHP 処理系が勝手に $previous を設定してくれる。 + このうち 1つ目のケースは、 finally 節の中でエラーを投げると PHP 処理系が勝手に $previous を設定してくれる。

<?php
@@ -263,7 +263,7 @@
 }

- この知識を元に、トークンの出力部を解析してみる。 + この知識を元に、トークンの出力部を解析してみる。

@@ -284,21 +284,21 @@ }

- 出力をおこなう catch 節を見てみると、 Throwable::getPrevious() を呼び出してエラーチェインを辿り、 Throwable::getLine() でエラーが発生した行数を取得している。その行数に 23 なるマジックナンバーを足し、フォーマット指定子 %c で出力している。 + 出力をおこなう catch 節を見てみると、 Throwable::getPrevious() を呼び出してエラーチェインを辿り、 Throwable::getLine() でエラーが発生した行数を取得している。その行数に 23 なるマジックナンバーを足し、フォーマット指定子 %c で出力している。

- フォーマット指定子 %c は、整数を ASCII コード と見做して印字する。トークン #base64_decode('SGVsbG8sIFdvcmxkIQ==')b であれば、ASCII コード 98 なので、75 行目で発生したエラー、 + フォーマット指定子 %c は、整数を ASCII コード と見做して印字する。トークン #base64_decode('SGVsbG8sIFdvcmxkIQ==')b であれば、ASCII コード 98 なので、75 行目で発生したエラー、

1, 20 => 0 / 0,

- によって表現されている。エラーを起こす方法はいろいろと考えられるが、今回はゼロ除算を使った。 + によって表現されている。エラーを起こす方法はいろいろと考えられるが、今回はゼロ除算を使った。

- それでは、エラーチェインを作る箇所、関数 f() を見ていく。 + それでは、エラーチェインを作る箇所、関数 f() を見ていく。

@@ -330,7 +330,7 @@ }

- 前述のように、 finally 節でエラーを投げると PHP 処理系が $previous を設定する。ここでは、エラーを繋げるために f() を再帰呼び出ししている。最初に f() を呼び出している箇所を確認すると、 + 前述のように、 finally 節でエラーを投げると PHP 処理系が $previous を設定する。ここでは、エラーを繋げるために f() を再帰呼び出ししている。最初に f() を呼び出している箇所を確認すると、

<?php
@@ -342,7 +342,7 @@
 }

- f() には 111 / 337 が渡されることがわかる。そこから 1 ずつ減らして再帰呼び出ししていき、0 より小さくなったら f() を引数なしで呼び出す。引数の数が足りないと呼び出しに失敗するので、再帰はここで止まる。 + f() には 111 / 337 が渡されることがわかる。そこから 1 ずつ減らして再帰呼び出ししていき、0 より小さくなったら f() を引数なしで呼び出す。引数の数が足りないと呼び出しに失敗するので、再帰はここで止まる。

@@ -372,11 +372,11 @@

- となっている。出力の際は catch したエラーの getPrevious() から処理を始めるので、1 番目の f() によるエラーは無視され、 f(0) によるエラー、 f(1) によるエラー、 f(2) によるエラー、と出力が進む。 + となっている。出力の際は catch したエラーの getPrevious() から処理を始めるので、1 番目の f() によるエラーは無視され、 f(0) によるエラー、 f(1) によるエラー、 f(2) によるエラー、と出力が進む。

- f()0 を渡したときは 12 行目にある match0 でゼロ除算が起こるので、行数が 12 となったエラーが投げられる。出力部ではこれに 23 を足した数を ASCII コードとして表示しているのだった。 12 + 2335、ASCII コードでは # である。これがトークンの 1文字目にあたる。 + f()0 を渡したときは 12 行目にある match0 でゼロ除算が起こるので、行数が 12 となったエラーが投げられる。出力部ではこれに 23 を足した数を ASCII コードとして表示しているのだった。 12 + 2335、ASCII コードでは # である。これがトークンの 1文字目にあたる。

@@ -384,7 +384,7 @@

おわりに

- 「行数」というのはトークン文字列をデコードする対象として優れている。 + 「行数」というのはトークン文字列をデコードする対象として優れている。

- しかし、こういった「変な」プログラムを何度も読んだり書いたりしていると、 __LINE__ を使うのはあまりにありきたりで退屈になる。では、他に行数を取得する手段はないか。こうして Throwable を思いつき、続けてエラーオブジェクトには $previous があることを思い出した。 + しかし、こういった「変な」プログラムを何度も読んだり書いたりしていると、 __LINE__ を使うのはあまりにありきたりで退屈になる。では、他に行数を取得する手段はないか。こうして Throwable を思いつき、続けてエラーオブジェクトには $previous があることを思い出した。

- 今回エラーを投げるのにゼロ除算を用いたのは、それがエラーを投げる最も短いコードだと考えたからである。もし 3バイト未満で Throwable なオブジェクトを投げる手段をご存じのかたがいらっしゃれば、ぜひご教示いただきたい。……と締める予定だったのだが、0/0 のところを存在しない定数にすれば、簡単に 1バイトを達成できた。ゼロ除算している箇所はちょうど 26 箇所あるので、アルファベットにでもしておけば意味ありげで良かったかもしれない。 + 今回エラーを投げるのにゼロ除算を用いたのは、それがエラーを投げる最も短いコードだと考えたからである。もし 3バイト未満で Throwable なオブジェクトを投げる手段をご存じのかたがいらっしゃれば、ぜひご教示いただきたい。……と締める予定だったのだが、0/0 のところを存在しない定数にすれば、簡単に 1バイトを達成できた。ゼロ除算している箇所はちょうど 26 箇所あるので、アルファベットにでもしておけば意味ありげで良かったかもしれない。

diff --git a/vhosts/blog/public/posts/2023-03-10/rewrite-this-blog-generator/index.html b/vhosts/blog/public/posts/2023-03-10/rewrite-this-blog-generator/index.html index 32a134a9..883b3ce5 100644 --- a/vhosts/blog/public/posts/2023-03-10/rewrite-this-blog-generator/index.html +++ b/vhosts/blog/public/posts/2023-03-10/rewrite-this-blog-generator/index.html @@ -55,22 +55,22 @@

はじめに

- このブログを構築するシステムを書き直したのは 2度目である。 元々立ち上げた当初は、静的サイトジェネレータである Hugo を使っていた。 それを Asciidoctor にいくつかのカスタムを加えた自前のジェネレータに移行したのが 2022年の11月ごろだ。 そして今回、スクラッチから書いた Deno 製のジェネレータに移行した。 + このブログを構築するシステムを書き直したのは 2度目である。元々立ち上げた当初は、静的サイトジェネレータである Hugo を使っていた。それを Asciidoctor にいくつかのカスタムを加えた自前のジェネレータに移行したのが 2022年の11月ごろだ。そして今回、スクラッチから書いた Deno 製のジェネレータに移行した。

- この記事では、移行の理由などを (主に将来の私へ向けて) 書き記しておく。 + この記事では、移行の理由などを (主に将来の私へ向けて) 書き記しておく。

Hugo から Asciidoctor へ

- 最初に断っておくと、Hugo は大変に優れた静的サイトジェネレータである。移行の理由の大半は、自分でジェネレータを書きたかったからに他ならない。 実のところ、この記事を執筆している現在、自作ジェネレータは Hugo よりも機能が劣っている。 例えば、Hugo を使っていたころはサポートしていた RSS フィードの生成は、まだ実装できていない。 + 最初に断っておくと、Hugo は大変に優れた静的サイトジェネレータである。移行の理由の大半は、自分でジェネレータを書きたかったからに他ならない。実のところ、この記事を執筆している現在、自作ジェネレータは Hugo よりも機能が劣っている。例えば、Hugo を使っていたころはサポートしていた RSS フィードの生成は、まだ実装できていない。

- 移行先のフォーマットとして AsciiDoc を選んだのは、Markdown よりも表現力に優れるからである。Markdown は広く使われている軽量マークアップ言語だが、以下のような欠点を持つ。 + 移行先のフォーマットとして AsciiDoc を選んだのは、Markdown よりも表現力に優れるからである。Markdown は広く使われている軽量マークアップ言語だが、以下のような欠点を持つ。

@@ -90,7 +90,7 @@

- AsciiDoc は Markdown に比べると普及していないが、上記の欠点は克服している。 + AsciiDoc は Markdown に比べると普及していないが、上記の欠点は克服している。

@@ -110,14 +110,14 @@

- なお、Hugo は AsciiDoc もサポートしているのだが、AsciiDoc を使う場合 Asciidoctor を別途インストールする必要があり、それならば最初から Asciidoctor でよかろうと移行を決めた。 + なお、Hugo は AsciiDoc もサポートしているのだが、AsciiDoc を使う場合 Asciidoctor を別途インストールする必要があり、それならば最初から Asciidoctor でよかろうと移行を決めた。

Asciidoctor から自前のジェネレータへ

- AsciiDoc は良いフォーマットだが、私には 1点不満があった。それは、高い表現力を担保するために記号が使い倒されており、エスケープが難しいという点だ (具体例を挙げたいのだが、何だったか覚えていない)。これは、多種多様な記号類を入力する必要のある技術ブログにとっては辛い問題である。この問題を解決するため、 + AsciiDoc は良いフォーマットだが、私には 1点不満があった。それは、高い表現力を担保するために記号が使い倒されており、エスケープが難しいという点だ (具体例を挙げたいのだが、何だったか覚えていない)。これは、多種多様な記号類を入力する必要のある技術ブログにとっては辛い問題である。この問題を解決するため、

- フォーマットが求められた。これに合致したのが、XML をベースとする DocBook (今回使っているのは、そのサブセットである Simplified DocBook) である。 + フォーマットが求められた。これに合致したのが、XML をベースとする DocBook (今回使っているのは、そのサブセットである Simplified DocBook) である。

- 実は、AsciiDoc と DocBook はおおよそ互換性がある。AsciiDoc で書かれた文書は (ほぼ) 情報ロスなしに DocBook へ変換でき、逆もまたしかりである。 よって、DocBook には、AsciiDoc と同等の表現力がある。 + 実は、AsciiDoc と DocBook はおおよそ互換性がある。AsciiDoc で書かれた文書は (ほぼ) 情報ロスなしに DocBook へ変換でき、逆もまたしかりである。よって、DocBook には、AsciiDoc と同等の表現力がある。

- XML の文法の厳密さについては、説明するまでもないだろう。また、単純な文法であることから実装が容易であり、事実上 Asciidoctor へロックインされる AsciiDoc とは異なり、さまざまな言語で多くのライブラリが存在する。 + XML の文法の厳密さについては、説明するまでもないだろう。また、単純な文法であることから実装が容易であり、事実上 Asciidoctor へロックインされる AsciiDoc とは異なり、さまざまな言語で多くのライブラリが存在する。

- 今回は、XML のパース自体も自分で書いている (これは何となく書きたかったからであり、合理的な理由があるわけではない。実装はサボりまくっているので XML のコメントが使えないといった制限がある)。 + 今回は、XML のパース自体も自分で書いている (これは何となく書きたかったからであり、合理的な理由があるわけではない。実装はサボりまくっているので XML のコメントが使えないといった制限がある)。

- XML という機械処理しやすいフォーマットを選ぶことには、機械的な変換や検査といった処理がおこないやすくなるといった利点もある。 欠点は軽量マークアップ言語と比べて冗長であることだが、書く際は補完などを用いるのでそれほど気にならない。 結局のところ、技術ブログの執筆を律速するのは調査と文章の記述であり、マークアップの手段は執筆時間に大した影響を与えない。 + XML という機械処理しやすいフォーマットを選ぶことには、機械的な変換や検査といった処理がおこないやすくなるといった利点もある。欠点は軽量マークアップ言語と比べて冗長であることだが、書く際は補完などを用いるのでそれほど気にならない。結局のところ、技術ブログの執筆を律速するのは調査と文章の記述であり、マークアップの手段は執筆時間に大した影響を与えない。

おわりに

- 2度のリライトを経て、記事のフォーマットとサイトジェネレータを上から下まで掌握した。 今後も改善のアイデアは多数あるので、じわじわと進めていきたいところだ。 + 2度のリライトを経て、記事のフォーマットとサイトジェネレータを上から下まで掌握した。今後も改善のアイデアは多数あるので、じわじわと進めていきたいところだ。

- 最後にもう一度書くのだが、Hugo は大変に優れた静的サイトジェネレータである。 無駄な拘りがなければこれを使うとよい。 私は無駄に拘ったので、ブログの記事を書く時間を潰してブログシステムを作ってしまった。 + 最後にもう一度書くのだが、Hugo は大変に優れた静的サイトジェネレータである。無駄な拘りがなければこれを使うとよい。私は無駄に拘ったので、ブログの記事を書く時間を潰してブログシステムを作ってしまった。

diff --git a/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html b/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html index 885433c3..4255b561 100644 --- a/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html +++ b/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html @@ -55,14 +55,14 @@

はじめに

- この記事では、PNG 画像として valid な範囲で最大限手抜きしたエンコーダを書く。 PNG 画像に対応したビューアであれば読み込めるが、圧縮効率については一切考えない。 また、実装には Go 言語を使うが、Go の標準ライブラリにあるさまざまなアルゴリズム (PNG 画像に関係する範囲だと、zlib や CRC32、Adler-32 など) は使わない。 + この記事では、PNG 画像として valid な範囲で最大限手抜きしたエンコーダを書く。PNG 画像に対応したビューアであれば読み込めるが、圧縮効率については一切考えない。また、実装には Go 言語を使うが、Go の標準ライブラリにあるさまざまなアルゴリズム (PNG 画像に関係する範囲だと、zlib や CRC32、Adler-32 など) は使わない。

PNG ファイルの基本構造

- PNG ファイルの基本構造は次のようになっている。 + PNG ファイルの基本構造は次のようになっている。

    @@ -84,18 +84,18 @@

- Chunk には画像データを入れる IDAT chunk、パレットデータを入れる PLTE chunk、テキストデータを入れる tEXt chunk などがあるが、 今回は最小構成ということで IDAT chunk (と IHDR chunk と IEND chunk) のみを用いる。 + Chunk には画像データを入れる IDAT chunk、パレットデータを入れる PLTE chunk、テキストデータを入れる tEXt chunk などがあるが、今回は最小構成ということで IDAT chunk (と IHDR chunk と IEND chunk) のみを用いる。

- 次節で、それぞれの具体的な構造を確認しつつ実装していく。 + 次節で、それぞれの具体的な構造を確認しつつ実装していく。

PNG のエンコーダを実装する

- 以下のソースコードをベースにする。 今回 PNG のデコーダは扱わないので、読み込みには Go の標準ライブラリ image/png を用いる。 + 以下のソースコードをベースにする。今回 PNG のデコーダは扱わないので、読み込みには Go の標準ライブラリ image/png を用いる。

package main
@@ -138,13 +138,13 @@
 }

- 以降は、writeSignaturewriteChunkIhdr などを実装していく。 + 以降は、writeSignaturewriteChunkIhdr などを実装していく。

PNG signature

- PNG signature は、PNG 画像の先頭に固定で付与されるバイト列で、8 バイトからなる。 + PNG signature は、PNG 画像の先頭に固定で付与されるバイト列で、8 バイトからなる。

    @@ -182,7 +182,7 @@

- CRLF や LF は、送信中に改行コードの変換が誤っておこなわれていないかどうかを検知するのに使われる。 + CRLF や LF は、送信中に改行コードの変換が誤っておこなわれていないかどうかを検知するのに使われる。

@@ -206,14 +206,14 @@ }

- encoding/binary パッケージの binary.Write を使い、固定の 8 バイトを書き込む。 + encoding/binary パッケージの binary.Write を使い、固定の 8 バイトを書き込む。

Chunk の構造

- IHDR chunk に進む前に、chunk 一般の構造を確認する。 + IHDR chunk に進む前に、chunk 一般の構造を確認する。

    @@ -235,7 +235,7 @@

- CRC (Cyclic Redundancy Check) は誤り検出符号の一種。Go 言語では hash/crc32 パッケージにあるが、今回はこれも自前で実装する。PNG の仕様書に C 言語のサンプルコードが載っている (D. Sample CRC implementation) ので、これを Go に移植する。 + CRC (Cyclic Redundancy Check) は誤り検出符号の一種。Go 言語では hash/crc32 パッケージにあるが、今回はこれも自前で実装する。PNG の仕様書に C 言語のサンプルコードが載っている (D. Sample CRC implementation) ので、これを Go に移植する。

var (
@@ -275,7 +275,7 @@
 }

- できた crc 関数を使って、chunk 一般を書き込む関数も用意しておこう。 + できた crc 関数を使って、chunk 一般を書き込む関数も用意しておこう。

func writeChunk(w io.Writer, chunkType string, data []byte) {
@@ -289,18 +289,18 @@
 }

- 仕様どおり、chunkTypedata から CRC を計算し、data の長さと合わせて書き込んでいる。 PNG では基本的に big endian を使うことに注意する。 + 仕様どおり、chunkTypedata から CRC を計算し、data の長さと合わせて書き込んでいる。PNG では基本的に big endian を使うことに注意する。

- 準備ができたところで、具体的な chunk をエンコードしていく。 + 準備ができたところで、具体的な chunk をエンコードしていく。

IHDR chunk

- IHDR chunk は最初に配置される chunk である。次のようなデータからなる。 + IHDR chunk は最初に配置される chunk である。次のようなデータからなる。

    @@ -369,7 +369,7 @@

- 今回ほとんどのデータは決め打ちするので、データに応じて変わるのは width と height だけになる。コードは次のようになる。 + 今回ほとんどのデータは決め打ちするので、データに応じて変わるのは width と height だけになる。コードは次のようになる。

import "bytes"
@@ -391,13 +391,13 @@
             

IDAT chunk

- IDAT chunk は、実際の画像データが格納された chunk である。IDAT chunk は deflate アルゴリズムにより圧縮され、zlib 形式で格納される。 + IDAT chunk は、実際の画像データが格納された chunk である。IDAT chunk は deflate アルゴリズムにより圧縮され、zlib 形式で格納される。

Zlib

- まずは zlib について確認する。おおよそ次のような構造になっている。 + まずは zlib について確認する。おおよそ次のような構造になっている。

    @@ -419,11 +419,11 @@

- 最初の 2 バイトにも意味はあるが、PNG では固定で構わない。 + 最初の 2 バイトにも意味はあるが、PNG では固定で構わない。

- Adler-32 も CRC と同じく誤り検出符号である。こちらも zlib の仕様書に C 言語でサンプルコードが記載されている (9. Appendix: Sample code) ので、Go に移植する。 + Adler-32 も CRC と同じく誤り検出符号である。こちらも zlib の仕様書に C 言語でサンプルコードが記載されている (9. Appendix: Sample code) ので、Go に移植する。

const adler32Base = 65521
@@ -444,11 +444,11 @@
 }

- 「データ」の部分には圧縮したデータが入るのだが、真面目に deflate アルゴリズムを実装する必要はない。Zlib には無圧縮のデータブロックを格納することができるので、これを使う。本来は、データの圧縮効率の悪いランダムなデータをそのまま格納するためのものだが、今回は deflate の実装をサボるために使う。 + 「データ」の部分には圧縮したデータが入るのだが、真面目に deflate アルゴリズムを実装する必要はない。Zlib には無圧縮のデータブロックを格納することができるので、これを使う。本来は、データの圧縮効率の悪いランダムなデータをそのまま格納するためのものだが、今回は deflate の実装をサボるために使う。

- 1 つの無圧縮ブロックには 65535 (216 - 1) バイトまで格納できる。それぞれのブロックは次のような構成になっている。 + 1 つの無圧縮ブロックには 65535 (216 - 1) バイトまで格納できる。それぞれのブロックは次のような構成になっている。

    @@ -502,11 +502,11 @@

    画像データ

    - では次に、zlib 形式で格納するデータを用意する。PNG 画像は次のような順にスキャンする。 画像の左上のピクセルから同じ行を横にスキャンしていき、一番右まで到達したら次の行の左に向かう。 右下のピクセルまで行けば終わり。要は Z 字型に進んでいく。 + では次に、zlib 形式で格納するデータを用意する。PNG 画像は次のような順にスキャンする。画像の左上のピクセルから同じ行を横にスキャンしていき、一番右まで到達したら次の行の左に向かう。右下のピクセルまで行けば終わり。要は Z 字型に進んでいく。

    - また、それぞれの行の先頭には、圧縮のためのフィルタタイプを指定する。 ただ、今回はその実装を省略するために、常にフィルタ 0 (何も加工しない) を使う。 + また、それぞれの行の先頭には、圧縮のためのフィルタタイプを指定する。ただ、今回はその実装を省略するために、常にフィルタ 0 (何も加工しない) を使う。

    @@ -533,7 +533,7 @@

    IEND chunk

    - 最後に IEND chunk を書き込む。これは PNG 画像の最後に配置される chunk で、PNG のデコーダはこの chunk に出会うとそこでデコードを停止する。 + 最後に IEND chunk を書き込む。これは PNG 画像の最後に配置される chunk で、PNG のデコーダはこの chunk に出会うとそこでデコードを停止する。

    @@ -549,7 +549,7 @@

    おわりに

    - 最後に全ソースコードを再掲しておく。 + 最後に全ソースコードを再掲しておく。

    package main
    diff --git a/vhosts/blog/public/posts/2023-04-04/phperkaigi-2023-report/index.html b/vhosts/blog/public/posts/2023-04-04/phperkaigi-2023-report/index.html
    index a086adb8..de619ab8 100644
    --- a/vhosts/blog/public/posts/2023-04-04/phperkaigi-2023-report/index.html
    +++ b/vhosts/blog/public/posts/2023-04-04/phperkaigi-2023-report/index.html
    @@ -70,7 +70,7 @@
               

    はじめに

    - 2023-03-23 から 2023-03-25 にかけて開催された、PHPerKaigi 2023 に参加した。 今年は 2つのセッションのスピーカーとして、また、当日スタッフとして参加した。 + 2023-03-23 から 2023-03-25 にかけて開催された、PHPerKaigi 2023 に参加した。今年は 2つのセッションのスピーカーとして、また、当日スタッフとして参加した。

    @@ -91,7 +91,7 @@

    スピーカーとして

    - これまでとの最大の違いとして、今回はスピーカーとして登壇した。まずはそれについて書く。2つのセッションで登壇した。 + これまでとの最大の違いとして、今回はスピーカーとして登壇した。まずはそれについて書く。2つのセッションで登壇した。

      @@ -131,22 +131,22 @@

    - PHPer チャレンジの話については後述する。 参照については、PHP を書き始めた頃からずっと疑問に思っていたので、仕組みを理解する良い機会となった。 + PHPer チャレンジの話については後述する。参照については、PHP を書き始めた頃からずっと疑問に思っていたので、仕組みを理解する良い機会となった。

    当日スタッフとして

    - 今回はスピーカーのみならず当日スタッフとしても参加した。 カンファレンスのスタッフとしての参加は初めてだったが、初参加のスタッフでもスムーズに作業ができるような仕組みが整えられていた。 + 今回はスピーカーのみならず当日スタッフとしても参加した。カンファレンスのスタッフとしての参加は初めてだったが、初参加のスタッフでもスムーズに作業ができるような仕組みが整えられていた。

    - PHPerKaigi は一般参加者の目線でもよくできたカンファレンスだなあという印象だったのだが、よりその思いを強くした。 なんとスタッフにとってもよくできたカンファレンスなのである。 + PHPerKaigi は一般参加者の目線でもよくできたカンファレンスだなあという印象だったのだが、よりその思いを強くした。なんとスタッフにとってもよくできたカンファレンスなのである。

    - 反省点は私自身の最大 HP がまったく足りていなかったことで、次の機会には最後まで動けるようにしたいところである。 + 反省点は私自身の最大 HP がまったく足りていなかったことで、次の機会には最後まで動けるようにしたいところである。

    @@ -155,7 +155,7 @@

    PHPer チャレンジ

    - 昨年に引き続き、弊社デジタルサーカス株式会社からのトークン問題の作題を担当した。 また、今年はさらに作成した問題を解説するセッションにも登壇した。 今年のトークンは、昨年の PHPerKaigi 2022 が終わった段階から作り始め、約半年かけて制作した。 + 昨年に引き続き、弊社デジタルサーカス株式会社からのトークン問題の作題を担当した。また、今年はさらに作成した問題を解説するセッションにも登壇した。今年のトークンは、昨年の PHPerKaigi 2022 が終わった段階から作り始め、約半年かけて制作した。

    - 問題の制作中は大変楽しかったが、まあやりすぎた。 いかに超絶技巧を凝らすかに注力してしまい、解く楽しさという観点を失ってしまったきらいがある。 + 問題の制作中は大変楽しかったが、まあやりすぎた。いかに超絶技巧を凝らすかに注力してしまい、解く楽しさという観点を失ってしまったきらいがある。

    @@ -217,7 +217,7 @@

    雑多な感想

    - なんかいろいろ。 + なんかいろいろ。

      @@ -259,7 +259,7 @@

      おわりに

      - 去年の参加レポでは、来年の目標として次を挙げた。 + 去年の参加レポでは、来年の目標として次を挙げた。

      @@ -283,23 +283,23 @@

      - プロポーザルに関しては採択されて登壇できたし、PHPer チャレンジは解説もおこなった。また、現地に行くだけでなく、当日スタッフとして参加した。 4つ目の PHPer チャレンジに関しては、今年は参加していない。 スタッフをやりながらだと入力する時間も探す時間も取れそうになかったのと、スタッフをやっている関係で少しだけ早く入手してしまうトークンがいくつか存在していたため。 + プロポーザルに関しては採択されて登壇できたし、PHPer チャレンジは解説もおこなった。また、現地に行くだけでなく、当日スタッフとして参加した。4つ目の PHPer チャレンジに関しては、今年は参加していない。スタッフをやりながらだと入力する時間も探す時間も取れそうになかったのと、スタッフをやっている関係で少しだけ早く入手してしまうトークンがいくつか存在していたため。

      - カンファレンス全体の感想についてだが、大規模なカンファレンスにオフラインで参加するのは今回が初めてだったので、その話をしたい。 + カンファレンス全体の感想についてだが、大規模なカンファレンスにオフラインで参加するのは今回が初めてだったので、その話をしたい。

      - オンラインとオフラインだと体験が別物になる。そもそもが似て非なるものなのだ。 向き不向きはあるだろうが、オンラインしか参加したことのないという方は、一度現地参加してみてはいかがだろうか。 + オンラインとオフラインだと体験が別物になる。そもそもが似て非なるものなのだ。向き不向きはあるだろうが、オンラインしか参加したことのないという方は、一度現地参加してみてはいかがだろうか。

      - さて、参加レポは去年も一昨年もこの言葉で締め括っているので、今年もそれで終わろうと思う。 + さて、参加レポは去年も一昨年もこの言葉で締め括っているので、今年もそれで終わろうと思う。

      - ではまた来年。 + ではまた来年。

      diff --git a/vhosts/blog/public/posts/2023-06-25/phpconfuk-2023-report/index.html b/vhosts/blog/public/posts/2023-06-25/phpconfuk-2023-report/index.html index 289c2c6f..93fe3e09 100644 --- a/vhosts/blog/public/posts/2023-06-25/phpconfuk-2023-report/index.html +++ b/vhosts/blog/public/posts/2023-06-25/phpconfuk-2023-report/index.html @@ -67,7 +67,7 @@

      はじめに

      - 2023-06-24 に開催された、PHP カンファレンス福岡 2023に参加した。 また、その前日に催された、非公式の前夜祭にも参加した。 前夜祭では、15分の登壇もおこなった。登壇の方の資料はこちら。 + 2023-06-24 に開催された、PHP カンファレンス福岡 2023に参加した。また、その前日に催された、非公式の前夜祭にも参加した。前夜祭では、15分の登壇もおこなった。登壇の方の資料はこちら。

      @@ -76,7 +76,7 @@

      前夜祭

      - ※セッションの題名と発表者名は、前夜祭イベントの connpass ページから引用。 + ※セッションの題名と発表者名は、前夜祭イベントの connpass ページから引用。

        @@ -84,7 +84,7 @@ スクラム(の一部)を導入してよくなったこと (asumikam さん)
        • - スクラムの「一部」を導入されたということでしたが、理想的な形で改善が進んでいるように見受けられました。 特に、ブランチ運用やデプロイ頻度、フィードバックサイクルに大きく変化が起きているのは驚くべき成果だと感じました。 + スクラムの「一部」を導入されたということでしたが、理想的な形で改善が進んでいるように見受けられました。特に、ブランチ運用やデプロイ頻度、フィードバックサイクルに大きく変化が起きているのは驚くべき成果だと感じました。
        @@ -93,7 +93,7 @@ 地方の小さな勉強会を一番の活動舞台にする (tomio さん)
        • - すさまじいほどの「熱」を感じました。 私自身、最近になってカンファレンスや勉強会への参加・登壇を活発におこなうようになったことで、頷く点が多かったです。 + すさまじいほどの「熱」を感じました。私自身、最近になってカンファレンスや勉強会への参加・登壇を活発におこなうようになったことで、頷く点が多かったです。
        @@ -103,7 +103,7 @@

        カンファレンス

        - ※セッションの題名と発表者名は、カンファレンスの fortee ページから引用。 + ※セッションの題名と発表者名は、カンファレンスの fortee ページから引用。

          @@ -111,7 +111,7 @@ 育成力 - エンジニアの才能を引き出す環境とチューターの立ち回り - (岡嵜 雄平 さん)
          • - ちょうど弊チームに新規メンバがジョインしたばかりで、オンボーディングプロセスについて考えていたところの発表でした。 すぐにすべてを取り入れるというわけにはいきませんが、弊社での新人育成プロセスの改善につながるヒントをいくつか得られたと思います。 + ちょうど弊チームに新規メンバがジョインしたばかりで、オンボーディングプロセスについて考えていたところの発表でした。すぐにすべてを取り入れるというわけにはいきませんが、弊社での新人育成プロセスの改善につながるヒントをいくつか得られたと思います。
          @@ -124,7 +124,7 @@
        • - 私自身、「オブジェクト指向」については色々と言いたいことがあるのですが、だいたいツイートしたこれとこれです。 + 私自身、「オブジェクト指向」については色々と言いたいことがあるのですが、だいたいツイートしたこれとこれです。
          • 「オブジェクト指向の話は、パラダイムの異なる複数の言語に触れているかどうかで見え方がまったく異なる印象がある。OOPはどうでもいいです (※個人の感想です)」 (Twitter のツイートへのリンク) @@ -142,7 +142,7 @@ その説明、コードコメントに書く?コミットメッセージに書く?プルリクエストに書く? (おかしょい/岡田正平 さん)
            • - Twitter にもツイートしましたが、完全に自分の意見と一致していたので、とても共感できました。 今後は社内のコードレビュー時に、こちらの資料を貼りつけることにします。 + Twitter にもツイートしましたが、完全に自分の意見と一致していたので、とても共感できました。今後は社内のコードレビュー時に、こちらの資料を貼りつけることにします。
          • @@ -153,7 +153,7 @@

            おわりに

            - 居住地域から離れた場所への遠征参加は初めてだったが、大変楽しい (しかも勉強にもなる!) 体験だった。 受け取った「熱」が冷める前に、自らの手を動かしていきたい。 + 居住地域から離れた場所への遠征参加は初めてだったが、大変楽しい (しかも勉強にもなる!) 体験だった。受け取った「熱」が冷める前に、自らの手を動かしていきたい。

            diff --git a/vhosts/blog/public/posts/2023-10-02/compile-php-runtime-to-wasm/index.html b/vhosts/blog/public/posts/2023-10-02/compile-php-runtime-to-wasm/index.html index 607edb5e..0e00dead 100644 --- a/vhosts/blog/public/posts/2023-10-02/compile-php-runtime-to-wasm/index.html +++ b/vhosts/blog/public/posts/2023-10-02/compile-php-runtime-to-wasm/index.html @@ -64,18 +64,18 @@

            はじめに

            - Emscripten を用いて PHP の処理系WebAssembly にコンパイルした。機能をある程度絞ることで、思ったよりも簡単に実現できたので、備忘録として記しておく。 + Emscripten を用いて PHP の処理系WebAssembly にコンパイルした。機能をある程度絞ることで、思ったよりも簡単に実現できたので、備忘録として記しておく。

            - なお、この記事では Emscripten や WebAssembly とは何か知っていることを前提とする。 + なお、この記事では Emscripten や WebAssembly とは何か知っていることを前提とする。

            バージョン情報

            - この記事中で使用するソフトウェア等のバージョンを記載する。 + この記事中で使用するソフトウェア等のバージョンを記載する。

              @@ -101,14 +101,14 @@

            - なお、Docker から下は Docker 上で導入するので、ホストマシンにはインストールしなくてよい。 + なお、Docker から下は Docker 上で導入するので、ホストマシンにはインストールしなくてよい。

            本記事のゴール

            - 先にこの記事のゴールを示しておく。これから示す手順のとおりに進めると、次のようなコードが動くようになる。 このコードはこのあと使うので、index.mjs の名前で保存しておくこと。 + 先にこの記事のゴールを示しておく。これから示す手順のとおりに進めると、次のようなコードが動くようになる。このコードはこのあと使うので、index.mjs の名前で保存しておくこと。

            import { readFile } from 'node:fs/promises';
            @@ -125,7 +125,7 @@
             console.log(`exit code: ${result}`);

            - 標準入力から与えたコードを WebAssembly にコンパイルされた PHP 処理系の上で実行している。このような php-wasm.mjs (とそこから呼び出される php-wasm.wasm) を作成する。 + 標準入力から与えたコードを WebAssembly にコンパイルされた PHP 処理系の上で実行している。このような php-wasm.mjs (とそこから呼び出される php-wasm.wasm) を作成する。

            @@ -134,7 +134,7 @@

            C のエントリポイントを書く

            - 先ほどのコードでも使っていたエントリポイントである php_wasm_run を用意する。 + 先ほどのコードでも使っていたエントリポイントである php_wasm_run を用意する。

            #include <stdio.h>
            @@ -163,32 +163,32 @@
             }

            - ほとんどはただの PHP の公開 API を使ったコードだが、Emscripten 向けの注意点が 2点ある。 + ほとんどはただの PHP の公開 API を使ったコードだが、Emscripten 向けの注意点が 2点ある。

            - まずは EMSCRIPTEN_KEEPALIVE について。 これは Emscripten が用意している特殊なマクロである。 このマクロが付与されている関数は、どこからも使用されていなくともコンパイル後の WebAssembly バイナリから削除されない。 もしこれを付け忘れると、未使用の関数とみなされ削除される。 + まずは EMSCRIPTEN_KEEPALIVE について。これは Emscripten が用意している特殊なマクロである。このマクロが付与されている関数は、どこからも使用されていなくともコンパイル後の WebAssembly バイナリから削除されない。もしこれを付け忘れると、未使用の関数とみなされ削除される。

            - 次に、コードを評価したあとに呼んでいる標準出力と標準エラー出力に対する改行の出力について。 出力バッファから出力させるためだけなら改行を出力させなくとも fflush() だけで事足りると考えたのだが、ないと動かなかったので追加した。 これにより、PHP コードの出力の後ろに余分な改行が追加されてしまう。 改行を出力せずともバッファを消費させる手段をご存知のかたはご教示願いたい。 + 次に、コードを評価したあとに呼んでいる標準出力と標準エラー出力に対する改行の出力について。出力バッファから出力させるためだけなら改行を出力させなくとも fflush() だけで事足りると考えたのだが、ないと動かなかったので追加した。これにより、PHP コードの出力の後ろに余分な改行が追加されてしまう。改行を出力せずともバッファを消費させる手段をご存知のかたはご教示願いたい。

            WebAssembly にコンパイルする

            - それでは WebAssembly にコンパイルしていこう。ここからは Dockerfile 上のコマンドとして操作を示す。 + それでは WebAssembly にコンパイルしていこう。ここからは Dockerfile 上のコマンドとして操作を示す。

            - まずは Emscripten 公式が提供している Docker イメージを使って、PHP 処理系と先ほど示した C 言語のソースコードを WebAssembly にコンパイルする。 + まずは Emscripten 公式が提供している Docker イメージを使って、PHP 処理系と先ほど示した C 言語のソースコードを WebAssembly にコンパイルする。

            FROM emscripten/emsdk:3.1.46 AS wasm-builder

            - 次に、php/php-src から PHP 処理系のソースコードを取得し、ビルドに必要な apt パッケージを取ってくる。 有効にする拡張を増やしたいなら、ここでインストールするパッケージも増やすことになるだろう。 + 次に、php/php-src から PHP 処理系のソースコードを取得し、ビルドに必要な apt パッケージを取ってくる。有効にする拡張を増やしたいなら、ここでインストールするパッケージも増やすことになるだろう。

            RUN git clone --depth=1 --branch=php-8.2.10 https://github.com/php/php-src
            @@ -203,7 +203,7 @@
                 :

            - 続けて、Emscripten のツールチェインを用いて PHP 処理系をビルドする。 + 続けて、Emscripten のツールチェインを用いて PHP 処理系をビルドする。

            RUN cd php-src && \
            @@ -230,31 +230,31 @@
                 :

            - ここまでと比べると少し複雑なので、それぞれ詳しく見ていこう。 + ここまでと比べると少し複雑なので、それぞれ詳しく見ていこう。

            - まず、buildconf は PHP 処理系をビルドするときに (Emscripten とは関係なく) 使うツールである。 このツールの最も重要な仕事は、configure の生成である。 + まず、buildconf は PHP 処理系をビルドするときに (Emscripten とは関係なく) 使うツールである。このツールの最も重要な仕事は、configure の生成である。

            - 次に configure するわけだが、ここで emconfigure を使う。 これを使うことで、Emscripten が上手く諸々のツールチェインを WebAssembly のビルド向けに調整しながら configure してくれる。 + 次に configure するわけだが、ここで emconfigure を使う。これを使うことで、Emscripten が上手く諸々のツールチェインを WebAssembly のビルド向けに調整しながら configure してくれる。

            - configure の後ろに指定してあるフラグは、通常の PHP 処理系のビルドで使う configure と同じなので、詳しくはそちらの cofigure --help を参照していただきたい。 ほとんどは、機能の無効化のために指定している (依存するライブラリを減らし、ビルドをより簡単にするため)。 + configure の後ろに指定してあるフラグは、通常の PHP 処理系のビルドで使う configure と同じなので、詳しくはそちらの cofigure --help を参照していただきたい。ほとんどは、機能の無効化のために指定している (依存するライブラリを減らし、ビルドをより簡単にするため)。

            - 通常の C のビルドなら、configure の次は make するところだが、ここでも emmake を使う。 役割はほとんど emconfigure と同様である。 指定してある EMCC_CFLAGS という環境変数は、Emscripten の C コンパイラへのフラグで、ここでは ERROR_ON_UNDEFINED_SYMBOLS を無効化している。 これにより、コンパイル中に出現した解決できなかったシンボルを無視するようになる (代わりに、そのシンボルを呼ぼうとしたタイミングで実行時エラーになる)。 すべての依存を完全に解決するのは面倒なので、あまり使わない機能については無視してもよいだろう。 + 通常の C のビルドなら、configure の次は make するところだが、ここでも emmake を使う。役割はほとんど emconfigure と同様である。指定してある EMCC_CFLAGS という環境変数は、Emscripten の C コンパイラへのフラグで、ここでは ERROR_ON_UNDEFINED_SYMBOLS を無効化している。これにより、コンパイル中に出現した解決できなかったシンボルを無視するようになる (代わりに、そのシンボルを呼ぼうとしたタイミングで実行時エラーになる)。すべての依存を完全に解決するのは面倒なので、あまり使わない機能については無視してもよいだろう。

            - ここまでを実行すると libs/libphp.a が生成される。これは後で使うので移動させている。 + ここまでを実行すると libs/libphp.a が生成される。これは後で使うので移動させている。

            - さて、PHP 処理系をライブラリ化できたので、次に先ほど載せた C のソースコードをビルドしていこう。 Dockerfile と同じ場所に php-wasm.c という名前で保存し、次のようにする。 + さて、PHP 処理系をライブラリ化できたので、次に先ほど載せた C のソースコードをビルドしていこう。Dockerfile と同じ場所に php-wasm.c という名前で保存し、次のようにする。

            COPY php-wasm.c /src/
            @@ -275,11 +275,11 @@
                 :

            - emcccc (C コンパイラ/リンカ) の Emscripten 版で、-c は「コンパイル」の意。 -o-I は普通の C コンパイラと同様、出力ファイルの指定とインクルードパスの指定である。 + emcccc (C コンパイラ/リンカ) の Emscripten 版で、-c は「コンパイル」の意。-o-I は普通の C コンパイラと同様、出力ファイルの指定とインクルードパスの指定である。

            - libphp.aphp-wasm.o が手に入ったので、これらをリンクして WebAssembly のバイナリとそのラッパである JavaScript ファイルを生成する。 これにも emcc コマンドを使う。 + libphp.aphp-wasm.o が手に入ったので、これらをリンクして WebAssembly のバイナリとそのラッパである JavaScript ファイルを生成する。これにも emcc コマンドを使う。

            RUN emcc \
            @@ -296,43 +296,43 @@
                 ;

            - それぞれのフラグについて解説する。 + それぞれのフラグについて解説する。

            - -s ENVIRONMENT=node は、生成する WebAssembly/JavaScript の実行環境を指定する。 今回は node を指定しているので、Node.js 向けのファイルが生成される。 + -s ENVIRONMENT=node は、生成する WebAssembly/JavaScript の実行環境を指定する。今回は node を指定しているので、Node.js 向けのファイルが生成される。

            - -s ERROR_ON_UNDEFINED_SYMBOLS=0 についてはすでに述べたので省略する。 + -s ERROR_ON_UNDEFINED_SYMBOLS=0 についてはすでに述べたので省略する。

            - -s EXPORTED_RUNTIME_METHODS='["ccall"]' は、生成される JavaScript から公開される API である。 すでに index.mjs で使用しているが、ccall('関数名', '返り値の型', ['仮引数の型', ...], ['実引数', ...]) のように使う。 + -s EXPORTED_RUNTIME_METHODS='["ccall"]' は、生成される JavaScript から公開される API である。すでに index.mjs で使用しているが、ccall('関数名', '返り値の型', ['仮引数の型', ...], ['実引数', ...]) のように使う。

            - -s EXPORT_ES6=1 は、JavaScript コードを ECMAScript 6 に準拠した module として生成する。 これを指定することで、require() ではなく import できる JavaScript を生成させられる。 + -s EXPORT_ES6=1 は、JavaScript コードを ECMAScript 6 に準拠した module として生成する。これを指定することで、require() ではなく import できる JavaScript を生成させられる。

            - -s INITIAL_MEMORY=16777216 は呼んで字のごとく。用途に合わせて適当に決めてほしい。 + -s INITIAL_MEMORY=16777216 は呼んで字のごとく。用途に合わせて適当に決めてほしい。

            - -s INVOKE_RUN=0 は、module をロードしたときに勝手に main() を呼ぶかどうか (だと思う)。 今回は php_wasm_run() しか使うつもりがないので切っている。 + -s INVOKE_RUN=0 は、module をロードしたときに勝手に main() を呼ぶかどうか (だと思う)。今回は php_wasm_run() しか使うつもりがないので切っている。

            - -s MODULARIZE=1 は、実質的にほぼ必須のオプションであり、1 を指定することで「WebAssembly module をインスタンス化する関数」をエクスポートするような JavaScript ファイルを生成するようになる。 これを指定しないと、生成物の JavaScript ファイルを読み込むと WebAssembly module が即座にインスタンス化されてしまい、起動のタイミングを制御できない。 + -s MODULARIZE=1 は、実質的にほぼ必須のオプションであり、1 を指定することで「WebAssembly module をインスタンス化する関数」をエクスポートするような JavaScript ファイルを生成するようになる。これを指定しないと、生成物の JavaScript ファイルを読み込むと WebAssembly module が即座にインスタンス化されてしまい、起動のタイミングを制御できない。

            - ここまで実行すると、php-wasm.jsphp-wasm.wasm が作られる。 では、ここからはこれらの実行環境を作っていこう。 + ここまで実行すると、php-wasm.jsphp-wasm.wasm が作られる。では、ここからはこれらの実行環境を作っていこう。

            - といっても、Node.js はビルトインで WebAssembly をサポートしているので、ほとんどやることはない。 先ほど掲載した JavaScript のコードは、Dockerfile と同じディレクトリに index.mjs で配置すること。 + といっても、Node.js はビルトインで WebAssembly をサポートしているので、ほとんどやることはない。先ほど掲載した JavaScript のコードは、Dockerfile と同じディレクトリに index.mjs で配置すること。

            FROM node:20.7
            @@ -349,7 +349,7 @@
                       

            実行

            - Dockerfilephp-wasm.cindex.mjs を用意したら、Docker コンテナをビルドして実行する。 + Dockerfilephp-wasm.cindex.mjs を用意したら、Docker コンテナをビルドして実行する。

            $ docker build -t php-wasm .
            @@ -363,7 +363,7 @@ exit code: 0

            まとめ

            - ここまでをまとめた Git リポジトリを用意した。 簡単にコンパイルできるので、興味があれば試してみてほしい。 + ここまでをまとめた Git リポジトリを用意した。簡単にコンパイルできるので、興味があれば試してみてほしい。

            diff --git a/vhosts/blog/public/posts/2023-10-13/i-entered-the-open-university-of-japan/index.html b/vhosts/blog/public/posts/2023-10-13/i-entered-the-open-university-of-japan/index.html index c8e1bf95..d6c63557 100644 --- a/vhosts/blog/public/posts/2023-10-13/i-entered-the-open-university-of-japan/index.html +++ b/vhosts/blog/public/posts/2023-10-13/i-entered-the-open-university-of-japan/index.html @@ -61,15 +61,15 @@
            放送大学に入学しました

            - とあるきっかけがあり、もう一度大学生をすることにしました。 仕事のほうも、これまでどおりフルタイムで続けていきます。 + とあるきっかけがあり、もう一度大学生をすることにしました。仕事のほうも、これまでどおりフルタイムで続けていきます。

            - 黙っているよりも公表したほうがモチベーションの向上に繋がるだろうと思い、このブログに記事として載せました。 + 黙っているよりも公表したほうがモチベーションの向上に繋がるだろうと思い、このブログに記事として載せました。

            - 以上、短いですが報告でした。 + 以上、短いですが報告でした。

            diff --git a/vhosts/blog/public/posts/2023-12-03/isucon-13/index.html b/vhosts/blog/public/posts/2023-12-03/isucon-13/index.html index a4fd2bc1..fdc94f3a 100644 --- a/vhosts/blog/public/posts/2023-12-03/isucon-13/index.html +++ b/vhosts/blog/public/posts/2023-12-03/isucon-13/index.html @@ -61,7 +61,7 @@

            はじめに

            - 先日 11月25日、ISUCON 13 に参加した。 ISUCON への参加は今回が初めてとなる。 私 nsfisis の1人チーム「うつしもゆ」として参加し、最終スコアは 13,580 点だった。使用言語は Go。 + 先日 11月25日、ISUCON 13 に参加した。ISUCON への参加は今回が初めてとなる。私 nsfisis の1人チーム「うつしもゆ」として参加し、最終スコアは 13,580 点だった。使用言語は Go。

            @@ -77,7 +77,7 @@

            目標

            - 今回は初参加ということもあり、目標を以下のように定めた。 + 今回は初参加ということもあり、目標を以下のように定めた。

              @@ -104,34 +104,34 @@

              戦略

              - ISUCON で高スコアを出す戦略については、戦闘力の高い方々が良質な記事を書いてくださっている。 ここでは、上述したような低い目標を達成するための戦略について書こうと思う。 + ISUCON で高スコアを出す戦略については、戦闘力の高い方々が良質な記事を書いてくださっている。ここでは、上述したような低い目標を達成するための戦略について書こうと思う。

              環境を破壊しない

              - ミドルウェアの設定やアプリケーションコードなど、変更を加えるあらゆるものは、必ずバックアップを取るか Git で管理する。 復旧不能になって環境ごと作り直すことだけは必ず避ける。 + ミドルウェアの設定やアプリケーションコードなど、変更を加えるあらゆるものは、必ずバックアップを取るか Git で管理する。復旧不能になって環境ごと作り直すことだけは必ず避ける。

              すぐに変更を取り消す

              - それでも壊してしまったときは、即座に変更を取り消す。壊れた理由を調べることに固執しない。 + それでも壊してしまったときは、即座に変更を取り消す。壊れた理由を調べることに固執しない。

              小さくデプロイする

              - 一度に複数の変更を加えず、可能な限り小さな単位でデプロイする。そしてその都度ベンチマークを走らせ、整合性チェックが通るかどうかを (当然速くなっているかどうかも) 確かめる。 + 一度に複数の変更を加えず、可能な限り小さな単位でデプロイする。そしてその都度ベンチマークを走らせ、整合性チェックが通るかどうかを (当然速くなっているかどうかも) 確かめる。

              使い慣れた道具を使う

              - 使用する言語、ミドルウェア、ツール類を、使い慣れたものに限定する。 「このツールのオプションはほとんどそらで指定できる」と言えるようなものだけを使う。 「自分では使ったことがないが ISUCON 強者がお勧めしていた」といった理由でツールを選定しない (もちろん、本番までに練習して習熟するという選択肢は存在する)。 + 使用する言語、ミドルウェア、ツール類を、使い慣れたものに限定する。「このツールのオプションはほとんどそらで指定できる」と言えるようなものだけを使う。「自分では使ったことがないが ISUCON 強者がお勧めしていた」といった理由でツールを選定しない (もちろん、本番までに練習して習熟するという選択肢は存在する)。

              @@ -139,14 +139,14 @@

              パフォーマンスの最適化

              - もっと強い人の記事を参考にしてほしい。 + もっと強い人の記事を参考にしてほしい。

              おわりに

              - 事前の準備も含めて、大変楽しいイベントだった。次回があるなら是非また参加したい。その際は、順位やスコアを目標として立てられるようになりたいものである。 + 事前の準備も含めて、大変楽しいイベントだった。次回があるなら是非また参加したい。その際は、順位やスコアを目標として立てられるようになりたいものである。

            diff --git a/vhosts/blog/public/posts/2023-12-31/2023-reflections/index.html b/vhosts/blog/public/posts/2023-12-31/2023-reflections/index.html index 5d5b219b..1e4f364b 100644 --- a/vhosts/blog/public/posts/2023-12-31/2023-reflections/index.html +++ b/vhosts/blog/public/posts/2023-12-31/2023-reflections/index.html @@ -55,14 +55,14 @@

            はじめに

            - 男もすなる年末の振り返りといふものを女もしてみむとてするなり。 + 男もすなる年末の振り返りといふものを女もしてみむとてするなり。

            登壇・カンファレンススタッフ

            - 勉強会やカンファレンスで登壇したりスタッフをしたりし始めたのは今年かららしい。 LT 等も含めて計 11 回の登壇をおこなった。 + 勉強会やカンファレンスで登壇したりスタッフをしたりし始めたのは今年かららしい。LT 等も含めて計 11 回の登壇をおこなった。

              @@ -133,7 +133,7 @@

              書いた記事

              - 登壇が増えたためか記事を書く機会が減ってしまった。 特に社内記事の本数が大きく減少しており、一昨年は約 100 本、昨年は約 60 本の社内記事を書いていたが、今年は 30 本強に留まった。 その頃と比べると文章を書く筋肉が衰えているように感じる。 + 登壇が増えたためか記事を書く機会が減ってしまった。特に社内記事の本数が大きく減少しており、一昨年は約 100 本、昨年は約 60 本の社内記事を書いていたが、今年は 30 本強に留まった。その頃と比べると文章を書く筋肉が衰えているように感じる。

                @@ -155,7 +155,7 @@

                作ったもの

                - ガラクタをいくつか作った。役には立たないが、作るのが楽しいという効用がある。 + ガラクタをいくつか作った。役には立たないが、作るのが楽しいという効用がある。

                  diff --git a/vhosts/blog/public/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file/index.html b/vhosts/blog/public/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file/index.html index 7c30e091..1e7cd5ee 100644 --- a/vhosts/blog/public/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file/index.html +++ b/vhosts/blog/public/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file/index.html @@ -66,14 +66,14 @@ NOTE
                  - この記事は Vim 駅伝 #136 の記事です。 + この記事は Vim 駅伝 #136 の記事です。

                  やりたいこと

                  - Neovim で空の PHP ファイルを開いたとき、そのファイルが置かれているディレクトリの構造に基づいて、自動的に namespace 宣言を挿入したい。具体的には、トップレベルの名前空間が MyNamespace であり、ファイル src/Foo/Bar/Baz.php を開いたときに、そのファイルが空であるなら、次のようなテンプレートが自動的に挿入されてほしい。 + Neovim で空の PHP ファイルを開いたとき、そのファイルが置かれているディレクトリの構造に基づいて、自動的に namespace 宣言を挿入したい。具体的には、トップレベルの名前空間が MyNamespace であり、ファイル src/Foo/Bar/Baz.php を開いたときに、そのファイルが空であるなら、次のようなテンプレートが自動的に挿入されてほしい。

                  <?php
                  @@ -89,29 +89,29 @@ Build type: Release
                   LuaJIT 2.1.1693350652

                  - 今回は Lua で処理を記述したため、Vim では動作しない。以下の説明でも Neovim に絞って述べる。 また、パス区切りがスラッシュである前提で記述したため、Windows には対応していない。 + 今回は Lua で処理を記述したため、Vim では動作しない。以下の説明でも Neovim に絞って述べる。また、パス区切りがスラッシュである前提で記述したため、Windows には対応していない。

                  ftplugin を用意する

                  - Neovim には特定のファイルタイプに対して特別な処理をおこなうための ftplugin と呼ばれる仕組みがある。 Neovim の設定を置くディレクトリ (例えば ~/.config/nvim) の配下に ftplugin/<FILE_TYPE>.vim または ftplugin/<FILE_TYPE>.lua というファイルを配置すると、その <FILE_TYPE> が読み込まれたときにそのファイルが自動的に実行される。 + Neovim には特定のファイルタイプに対して特別な処理をおこなうための ftplugin と呼ばれる仕組みがある。Neovim の設定を置くディレクトリ (例えば ~/.config/nvim) の配下に ftplugin/<FILE_TYPE>.vim または ftplugin/<FILE_TYPE>.lua というファイルを配置すると、その <FILE_TYPE> が読み込まれたときにそのファイルが自動的に実行される。

                  - 今回は、Neovim がデフォルトで用意している PHP 用 ftplugin が動作したあとに追加の処理をおこないたいので、after/ftplugin/php.{vim,lua} というファイルを配置する。名前から察せられるとおり、after/ftplugin 以下のファイルは ftplugin 以下のファイルよりもあとに実行される。 + 今回は、Neovim がデフォルトで用意している PHP 用 ftplugin が動作したあとに追加の処理をおこないたいので、after/ftplugin/php.{vim,lua} というファイルを配置する。名前から察せられるとおり、after/ftplugin 以下のファイルは ftplugin 以下のファイルよりもあとに実行される。

                  - この記事では Lua で処理を記述するため、拡張子には .lua を用いる。 これ以降載せるコードは、すべて after/ftplugin/php.lua の中に記述している。 + この記事では Lua で処理を記述するため、拡張子には .lua を用いる。これ以降載せるコードは、すべて after/ftplugin/php.lua の中に記述している。

                  二重読み込みを防ぐ

                  - ファイルタイプは読み込んだあとに変更されることもあるので、ftplugin は複数回実行されうる。 二重読み込みを防ぐために、did_ftplugin_<FILE_TYPE>_after というバッファローカル変数を定義しておくのが慣習となっている。 + ファイルタイプは読み込んだあとに変更されることもあるので、ftplugin は複数回実行されうる。二重読み込みを防ぐために、did_ftplugin_<FILE_TYPE>_after というバッファローカル変数を定義しておくのが慣習となっている。

                  if vim.b.did_ftplugin_php_after then
                  @@ -126,7 +126,7 @@ vim.b.did_ftplugin_php_after = true
                               

                  実装する

                  - では実装していこう。今回私は次のようなロジックとした。以降、「今 Neovim で開いた PHP ファイル」のことを「対象ファイル」と呼ぶことにする。 + では実装していこう。今回私は次のようなロジックとした。以降、「今 Neovim で開いた PHP ファイル」のことを「対象ファイル」と呼ぶことにする。

                    @@ -156,7 +156,7 @@ vim.b.did_ftplugin_php_after = true

                    - 実装を簡単にするため、Composer を用いない場合や PSR 4 以外のオートロード規則を使う場合には対応しない。少々長くなるが、以下にスクリプト全文を載せる。 + 実装を簡単にするため、Composer を用いない場合や PSR 4 以外のオートロード規則を使う場合には対応しない。少々長くなるが、以下にスクリプト全文を載せる。

                    if vim.b.did_ftplugin_php_after then
                    @@ -277,7 +277,7 @@ vim.b.did_ftplugin_php_after = true
                                 

                    おわりに

                    - 簡易的な実装だが、多くのケースではうまく動いているようだ。 最大の問題は PSR 4 に準拠しないフレームワークを用いているとまったく役に立たないことで、今まさに職場で困っている。 こちらはいずれ改良したい。 + 簡易的な実装だが、多くのケースではうまく動いているようだ。最大の問題は PSR 4 に準拠しないフレームワークを用いているとまったく役に立たないことで、今まさに職場で困っている。こちらはいずれ改良したい。

                  diff --git a/vhosts/blog/public/posts/2024-02-03/install-wireguard-on-personal-server/index.html b/vhosts/blog/public/posts/2024-02-03/install-wireguard-on-personal-server/index.html index 1132448a..9b8c1815 100644 --- a/vhosts/blog/public/posts/2024-02-03/install-wireguard-on-personal-server/index.html +++ b/vhosts/blog/public/posts/2024-02-03/install-wireguard-on-personal-server/index.html @@ -67,7 +67,7 @@

                  はじめに

                  - 個人用サービスのセルフホストに使っているサーバに WireGuard を導入する作業をしたのでメモ。 + 個人用サービスのセルフホストに使っているサーバに WireGuard を導入する作業をしたのでメモ。

                  @@ -89,20 +89,20 @@

                - 後ろの IP アドレスは VPN 内で使用するプライベート IP アドレス。 + 後ろの IP アドレスは VPN 内で使用するプライベート IP アドレス。

                WireGuard のインストール: サーバ

                - まずは個人用サービスをホストしている Ubuntu のサーバに WireGuard をインストールする。 + まずは個人用サービスをホストしている Ubuntu のサーバに WireGuard をインストールする。

                $ sudo apt install wireguard

                - 次に、WireGuard で使用する鍵を生成する。 + 次に、WireGuard で使用する鍵を生成する。

                $ wg genkey | sudo tee /etc/wireguard/server.key | wg pubkey | sudo tee /etc/wireguard/server.pub
                @@ -112,7 +112,7 @@ $ sudo chmod 600 /etc/wireguard/server.{key,pub}

                WireGuard のインストール: クライアント

                - 公式サイトから各 OS 向けのクライアントソフトウェアを入手し、インストールする。次に、設定をおこなう。 + 公式サイトから各 OS 向けのクライアントソフトウェアを入手し、インストールする。次に、設定をおこなう。

                # クライアント 1 の場合
                @@ -136,14 +136,14 @@ $ sudo chmod 600 /etc/wireguard/server.{key,pub}
                Endpoint = <サーバの外部 IP アドレス>:51820

            - PrivateKeyPublicKey は鍵ファイルのパスではなく中身を書くことに注意。 + PrivateKeyPublicKey は鍵ファイルのパスではなく中身を書くことに注意。

            WireGuard の設定

            - 一度サーバへ戻り、WireGuard の設定ファイルを書く。 + 一度サーバへ戻り、WireGuard の設定ファイルを書く。

            $ sudo vim /etc/wireguard/wg0.conf
            @@ -163,7 +163,7 @@ $ sudo chmod 600 /etc/wireguard/server.{key,pub}
    AllowedIPs = 10.10.1.3/32

- 次に、WireGuard のサービスを起動する。 + 次に、WireGuard のサービスを起動する。

$ sudo systemctl enable wg-quick@wg0
@@ -173,7 +173,7 @@ $ sudo systemctl start wg-quick@wg0

ファイアウォールの設定

- 続けてファイアウォールを設定する。まずは WireGuard が使用する UDP のポートを開き、wg0 を通る通信を許可する。 + 続けてファイアウォールを設定する。まずは WireGuard が使用する UDP のポートを開き、wg0 を通る通信を許可する。

$ sudo ufw allow 51820/udp
@@ -181,14 +181,14 @@ $ sudo ufw allow in on wg0
 $ sudo ufw allow out on wg0

- 次に、80 や 443 などの必要なポートについて、wg0 を経由してのアクセスのみ許可する。 + 次に、80 や 443 などの必要なポートについて、wg0 を経由してのアクセスのみ許可する。

$ sudo ufw allow in on wg0 to any port 80 proto tcp
 $ sudo ufw allow in on wg0 to any port 443 proto tcp

- 最後に、ufw を有効にする。 + 最後に、ufw を有効にする。

$ sudo ufw status
@@ -198,14 +198,14 @@ $ sudo ufw enable

接続する

- これで、各クライアントで VPN を有効にすると、当該サーバの 80 ポートや 443 ポートにアクセスできるようになったはずだ。念のため VPN を切った状態でアクセスできないことも確認しておくとよいだろう。 + これで、各クライアントで VPN を有効にすると、当該サーバの 80 ポートや 443 ポートにアクセスできるようになったはずだ。念のため VPN を切った状態でアクセスできないことも確認しておくとよいだろう。

追記: 80 番ポートについて

- Let's Encrypt でサーバの証明書を取得している場合、80 番ポートを空けておく必要がある。気づかないうちに証明書が切れないよう注意。 + Let's Encrypt でサーバの証明書を取得している場合、80 番ポートを空けておく必要がある。気づかないうちに証明書が切れないよう注意。

diff --git a/vhosts/blog/public/posts/2024-02-10/yapcjapan-2024-report/index.html b/vhosts/blog/public/posts/2024-02-10/yapcjapan-2024-report/index.html index 47a19be7..27f11038 100644 --- a/vhosts/blog/public/posts/2024-02-10/yapcjapan-2024-report/index.html +++ b/vhosts/blog/public/posts/2024-02-10/yapcjapan-2024-report/index.html @@ -67,14 +67,14 @@

はじめに

- 2024-02-10 に開催された、YAPC::Hiroshima 2024 に参加した。 + 2024-02-10 に開催された、YAPC::Hiroshima 2024 に参加した。

セッションの感想

- ※セッションの題名と発表者名は、カンファレンスの fortee ページから引用。 + ※セッションの題名と発表者名は、カンファレンスの fortee ページから引用。

    @@ -115,11 +115,11 @@

    おわりに

    - 最高だった。特に、杜甫々氏の講演を生で拝聴できたのは、感慨とともに大いに刺激となった。次回の YAPC にも是非参加したい。 + 最高だった。特に、杜甫々氏の講演を生で拝聴できたのは、感慨とともに大いに刺激となった。次回の YAPC にも是非参加したい。

    - P.S. Perl を書いたことがなくとも十二分に楽しめるイベントなので、「Perl を書かない」という理由で参加しなかったかたは、次回是非参加を検討してみてほしい。 + P.S. Perl を書いたことがなくとも十二分に楽しめるイベントなので、「Perl を書かない」という理由で参加しなかったかたは、次回是非参加を検討してみてほしい。

    diff --git a/vhosts/blog/public/posts/2024-02-22/phpkansai-2024-report/index.html b/vhosts/blog/public/posts/2024-02-22/phpkansai-2024-report/index.html index cb722b51..4cb0c230 100644 --- a/vhosts/blog/public/posts/2024-02-22/phpkansai-2024-report/index.html +++ b/vhosts/blog/public/posts/2024-02-22/phpkansai-2024-report/index.html @@ -67,14 +67,14 @@

    はじめに

    - 2024-02-11 に開催された、PHPカンファレンス関西 2024 に参加した。 + 2024-02-11 に開催された、PHPカンファレンス関西 2024 に参加した。

    セッションの感想

    - ※セッションの題名と発表者名は、カンファレンスの fortee ページから引用。 + ※セッションの題名と発表者名は、カンファレンスの fortee ページから引用。

      @@ -111,11 +111,11 @@

      おわりに

      - 本カンファレンスの前日 2024-02-10 は YAPC::Hiroshima に参加しており、2日連続のカンファレンスとなった。かなり疲れはしたが、その分充実した週末となったように思う。 + 本カンファレンスの前日 2024-02-10 は YAPC::Hiroshima に参加しており、2日連続のカンファレンスとなった。かなり疲れはしたが、その分充実した週末となったように思う。

      - 翌3月は PHPerKaigi 2024、4月は PHPカンファレンス小田原 2024 があり、いずれもスタッフ兼スピーカーで参加予定である。 今度は提供する側として、満足のいくカンファレンスになるようにしたい。 + 翌3月は PHPerKaigi 2024、4月は PHPカンファレンス小田原 2024 があり、いずれもスタッフ兼スピーカーで参加予定である。今度は提供する側として、満足のいくカンファレンスになるようにしたい。

      diff --git a/vhosts/blog/public/posts/2024-03-17/phperkaigi-2024-report/index.html b/vhosts/blog/public/posts/2024-03-17/phperkaigi-2024-report/index.html index 563ae322..a906374b 100644 --- a/vhosts/blog/public/posts/2024-03-17/phperkaigi-2024-report/index.html +++ b/vhosts/blog/public/posts/2024-03-17/phperkaigi-2024-report/index.html @@ -70,7 +70,7 @@

      はじめに

      - 2024-03-07 から 2024-03-09 にかけて開催された、PHPerKaigi 2024 に参加した。 今年はスピーカーとして、また、コアスタッフとして参加した。 + 2024-03-07 から 2024-03-09 にかけて開催された、PHPerKaigi 2024 に参加した。今年はスピーカーとして、また、コアスタッフとして参加した。

      @@ -95,7 +95,7 @@

      スピーカーとして

      - 昨年に続き、スピーカーとして登壇をおこなった。 + 昨年に続き、スピーカーとして登壇をおこなった。

        @@ -114,14 +114,14 @@

      - WebAssembly の VM を PHP で実装し、実装に至るまでの道程や WebAssembly の特徴、言語処理系を作る楽しさについて語った。 タイトルにある「WebAssembly を理解する」という目的が達成できるようなトークだったかと言われると疑問は残るものの、実際に作った人にしかできない話をすることはできたと思う。 + WebAssembly の VM を PHP で実装し、実装に至るまでの道程や WebAssembly の特徴、言語処理系を作る楽しさについて語った。タイトルにある「WebAssembly を理解する」という目的が達成できるようなトークだったかと言われると疑問は残るものの、実際に作った人にしかできない話をすることはできたと思う。

      コアスタッフとして

      - 昨年は当日スタッフとして参加したが、今年はコアスタッフとして運営に参加した。 今年はコードゴルフ企画を提案し、その準備とシステムの開発、当日の運用をおこなった。 そのシステムは現在も下記の URL から閲覧でき、当日出題された問題や参加者の方々の回答が見られる。 + 昨年は当日スタッフとして参加したが、今年はコアスタッフとして運営に参加した。今年はコードゴルフ企画を提案し、その準備とシステムの開発、当日の運用をおこなった。そのシステムは現在も下記の URL から閲覧でき、当日出題された問題や参加者の方々の回答が見られる。

      @@ -129,7 +129,7 @@

      - システムの開発完了や問題の作成完了はスケジュールギリギリとなったのだが、当日はそこそこ安定して稼動していたのではないかと思う。 + システムの開発完了や問題の作成完了はスケジュールギリギリとなったのだが、当日はそこそこ安定して稼動していたのではないかと思う。

      @@ -142,15 +142,15 @@

      - 今回一番楽しみにしていたセッションであり、期待どおりの面白さだった。 私も今回 VM を作るというテーマで登壇したこともあり、高い解像度で受け取ることができたように思う。 + 今回一番楽しみにしていたセッションであり、期待どおりの面白さだった。私も今回 VM を作るというテーマで登壇したこともあり、高い解像度で受け取ることができたように思う。

      - P.S. Ask the Speaker で話した、Ruby VM (written in PHP) on PHP VM (compiled to Wasm) on Wasm VM (written in PHP) on PHP というアイデアは「マジ」なので、続報をお待ちください (自作 Wasm runtime に不足している機能を鋭意実装中です)。 + P.S. Ask the Speaker で話した、Ruby VM (written in PHP) on PHP VM (compiled to Wasm) on Wasm VM (written in PHP) on PHP というアイデアは「マジ」なので、続報をお待ちください (自作 Wasm runtime に不足している機能を鋭意実装中です)。

      - 2024-07-07 追記: コミット a312e95 で、ついに Ruby VM on PHP VM on Wasm VM on PHP を実現した。現時点での動かしかたは README に記載している。 + 2024-07-07 追記: コミット a312e95 で、ついに Ruby VM on PHP VM on Wasm VM on PHP を実現した。現時点での動かしかたは README に記載している。

    @@ -158,7 +158,7 @@

    おわりに

    - 今年はスピーカーとスタッフともに開発を伴うものだったので (Wasm 処理系とコードゴルフシステム)、両者がぶつかった結果として準備段階は去年よりも大変になった。 + 今年はスピーカーとスタッフともに開発を伴うものだったので (Wasm 処理系とコードゴルフシステム)、両者がぶつかった結果として準備段階は去年よりも大変になった。

    @@ -166,19 +166,19 @@

    - ただ、それでもコアスタッフとして半年ほど関わっただけに、終わってみると感慨深い。 例年どおり、お祭のような活気・熱気を感じることができた。 + ただ、それでもコアスタッフとして半年ほど関わっただけに、終わってみると感慨深い。例年どおり、お祭のような活気・熱気を感じることができた。

    - 来月は、また登壇とスタッフ (こちらは当日スタッフ) をおこなう PHP カンファレンス小田原 があるので、良いトーク・良いカンファレンスを作れるようにしたい。 + 来月は、また登壇とスタッフ (こちらは当日スタッフ) をおこなう PHP カンファレンス小田原 があるので、良いトーク・良いカンファレンスを作れるようにしたい。

    - さて、参加レポは例年この言葉で締め括っているので、今年もそれで終わろうと思う。 + さて、参加レポは例年この言葉で締め括っているので、今年もそれで終わろうと思う。

    - ではまた来年。 + ではまた来年。

    diff --git a/vhosts/blog/public/posts/2024-03-20/my-bucket-list/index.html b/vhosts/blog/public/posts/2024-03-20/my-bucket-list/index.html index a4a6174a..e1449afa 100644 --- a/vhosts/blog/public/posts/2024-03-20/my-bucket-list/index.html +++ b/vhosts/blog/public/posts/2024-03-20/my-bucket-list/index.html @@ -56,27 +56,27 @@

- これは眠れない夜にノートへ書き散らした文をなんとか文章の体裁に直したものであり、およそ論理と呼べるものを期待してはならぬ。 + これは眠れない夜にノートへ書き散らした文をなんとか文章の体裁に直したものであり、およそ論理と呼べるものを期待してはならぬ。

- Knuth 曰くプログラミングは文芸である。断っておくが、労役に伴うプロダクティブでプラクティカルな行為を指してそう言っているのではない (Knuth がどう考えているかは知らないが、少なくとも私にとっては)。いわゆる趣味プログラミング、穢れなき自由意志の下で記述されるプログラムとはすなわち、絵描きにとっての絵、文字書きにとっての文章に等しい。プログラムとは、ソースコードとは、芸術作品の一形態なのである。 + Knuth 曰くプログラミングは文芸である。断っておくが、労役に伴うプロダクティブでプラクティカルな行為を指してそう言っているのではない (Knuth がどう考えているかは知らないが、少なくとも私にとっては)。いわゆる趣味プログラミング、穢れなき自由意志の下で記述されるプログラムとはすなわち、絵描きにとっての絵、文字書きにとっての文章に等しい。プログラムとは、ソースコードとは、芸術作品の一形態なのである。

- この人生でプログラミングという行為に魅せられたからには、美しい作品を遺さねばならぬ。すなわち、簡潔で、理解しやすく、凝縮され、機能的で、速く、軽く、よい名前を持ち、うまく動くものをだ。 + この人生でプログラミングという行為に魅せられたからには、美しい作品を遺さねばならぬ。すなわち、簡潔で、理解しやすく、凝縮され、機能的で、速く、軽く、よい名前を持ち、うまく動くものをだ。

- 何を作りたいかは各々異なるであろうが、私にとっては車輪の再発明として知られる自作○○である。 + 何を作りたいかは各々異なるであろうが、私にとっては車輪の再発明として知られる自作○○である。

- 車輪の再発明を恐れてはいけない。これを批判する人間というのは、プロダクティビティやプラクティカリティにフォーカスするエンジニアという人種である。今私が表現者たろうとするなら、自らの手で自らの車輪を作ることに何の恐れを抱く必要があろうか。 + 車輪の再発明を恐れてはいけない。これを批判する人間というのは、プロダクティビティやプラクティカリティにフォーカスするエンジニアという人種である。今私が表現者たろうとするなら、自らの手で自らの車輪を作ることに何の恐れを抱く必要があろうか。

- そう、これが私の死ぬまでに作る自作○○一覧あるいは人生の TODO リストである (現時点ですでに部分的あるいは全面的に達成しているものを含む)。 + そう、これが私の死ぬまでに作る自作○○一覧あるいは人生の TODO リストである (現時点ですでに部分的あるいは全面的に達成しているものを含む)。

    @@ -134,11 +134,11 @@

- 選定理由は作りたいということのほかにない。そこに題材とキャンバスがあり絵筆と絵具があれば、生きとし生けるもの、いづれかコードを書かざりける。 + 選定理由は作りたいということのほかにない。そこに題材とキャンバスがあり絵筆と絵具があれば、生きとし生けるもの、いづれかコードを書かざりける。

- おお、願わくは、私にこれらを生み出すだけの時間があらんことを。 + おお、願わくは、私にこれらを生み出すだけの時間があらんことを。

diff --git a/vhosts/blog/public/posts/2024-04-14/phpcon-odawara-2024-report/index.html b/vhosts/blog/public/posts/2024-04-14/phpcon-odawara-2024-report/index.html index 422ddd3d..4f7abef8 100644 --- a/vhosts/blog/public/posts/2024-04-14/phpcon-odawara-2024-report/index.html +++ b/vhosts/blog/public/posts/2024-04-14/phpcon-odawara-2024-report/index.html @@ -70,14 +70,14 @@

はじめに

- 2024-04-13 に開催されたPHP カンファレンス小田原に、スピーカーとして、また当日スタッフとして参加した。 + 2024-04-13 に開催されたPHP カンファレンス小田原に、スピーカーとして、また当日スタッフとして参加した。

スピーカーとして

- PHP 処理系の JIT コンパイルにおける PHP 8.4 での変更について、登壇をおこなった。 + PHP 処理系の JIT コンパイルにおける PHP 8.4 での変更について、登壇をおこなった。

    @@ -96,30 +96,30 @@

- 今回、どこから話を始めるか大いに迷ったのだが、最終的には PHP 処理系の opcode や VM といった概念は既知のものとし、そこから JIT コンパイルへ繋げるといった構成にした。 + 今回、どこから話を始めるか大いに迷ったのだが、最終的には PHP 処理系の opcode や VM といった概念は既知のものとし、そこから JIT コンパイルへ繋げるといった構成にした。

- PHP の処理系がスクリプトを opcode へ変換する過程については、ちょうど同じカンファレンスのめもりーさんの発表あたりを参考にしていただくとよいだろう。 また、新しい IR についてより詳しく知りたいという方は、スライド末尾の「参考資料」にあるリンクを参照いただくのがよいかと思う。 + PHP の処理系がスクリプトを opcode へ変換する過程については、ちょうど同じカンファレンスのめもりーさんの発表あたりを参考にしていただくとよいだろう。また、新しい IR についてより詳しく知りたいという方は、スライド末尾の「参考資料」にあるリンクを参照いただくのがよいかと思う。

- Tracing JIT の発火条件や、IR を使って実現される最適化方法など、調べたものの発表に入らなかった話がごまんとあるので、これもどこかに持っていければと考えている。 + Tracing JIT の発火条件や、IR を使って実現される最適化方法など、調べたものの発表に入らなかった話がごまんとあるので、これもどこかに持っていければと考えている。

スタッフとして

- 当日スタッフとして前日の準備と当日の運営をおこなった。今回はモノの移動が比較的 (比較対象: PHPerKaigi) 少なく、体力にはかなり余裕があった。 + 当日スタッフとして前日の準備と当日の運営をおこなった。今回はモノの移動が比較的 (比較対象: PHPerKaigi) 少なく、体力にはかなり余裕があった。

- 自分の担当範囲内では、一度タイムキーパー係のときに時間を思いきり間違えた以外は、スムーズに進められたかと思う。 + 自分の担当範囲内では、一度タイムキーパー係のときに時間を思いきり間違えた以外は、スムーズに進められたかと思う。

- また、これはコアスタッフの方々のおかげだろうが、初開催としては大きなトラブルなく終わったと言えるのではないだろうか。 + また、これはコアスタッフの方々のおかげだろうが、初開催としては大きなトラブルなく終わったと言えるのではないだろうか。

@@ -174,11 +174,11 @@

おわりに

- 怒涛の月刊 PHP カンファレンスも折り返しとなったが、まだまだ新鮮に楽しい。 + 怒涛の月刊 PHP カンファレンスも折り返しとなったが、まだまだ新鮮に楽しい。

- また今度、カンファレンスで会いましょう (震源地がよくわかっていないのだけれど、575 が流行っているらしい)。 + また今度、カンファレンスで会いましょう (震源地がよくわかっていないのだけれど、575 が流行っているらしい)。

diff --git a/vhosts/blog/public/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd/index.html b/vhosts/blog/public/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd/index.html index 6d21b1d2..bf281982 100644 --- a/vhosts/blog/public/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd/index.html +++ b/vhosts/blog/public/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd/index.html @@ -69,12 +69,12 @@ NOTE
- この記事は、2022-11-17 にデジタルサーカス株式会社 の社内 Qiita Team に公開された記事をベースに、加筆修正して一般公開したものです。 + この記事は、2022-11-17 にデジタルサーカス株式会社 の社内 Qiita Team に公開された記事をベースに、加筆修正して一般公開したものです。

- ハマったのでメモ。 + ハマったのでメモ。

@@ -82,7 +82,7 @@

GitLab CI/CD について

- GitLab CI/CD では、Docker executor を用いて任意の Docker image 上でスクリプトを走らせることができる。 + GitLab CI/CD では、Docker executor を用いて任意の Docker image 上でスクリプトを走らせることができる。

@@ -99,11 +99,11 @@ when: always

- ここで、script に指定したコマンドが失敗する (exit status が 0 以外になる) と、即座に実行が停止され、ジョブは失敗する。 + ここで、script に指定したコマンドが失敗する (exit status が 0 以外になる) と、即座に実行が停止され、ジョブは失敗する。

- では、次のようなケースだとどうなるか。 + では、次のようなケースだとどうなるか。

hello-world:
@@ -116,14 +116,14 @@
   when: always

- 失敗するコマンドをパイプに接続した。通常 Bash では、パイプの最後のコマンドの exit code が全体の exit code になる。 + 失敗するコマンドをパイプに接続した。通常 Bash では、パイプの最後のコマンドの exit code が全体の exit code になる。

pipefail オプションについて

- 前述したようなケースにおいて、途中で失敗したときに全体を失敗させるには、pipefail オプションを有効にする。 + 前述したようなケースにおいて、途中で失敗したときに全体を失敗させるには、pipefail オプションを有効にする。

# On にする
@@ -132,7 +132,7 @@
 set +o pipefail

- こうすると、パイプ全体が失敗するようになる。 この設定は、デフォルトだと off になっている。 + こうすると、パイプ全体が失敗するようになる。この設定は、デフォルトだと off になっている。

@@ -140,7 +140,7 @@

発生した問題

- 次のような GitLab CI/CD ジョブが失敗してしまった。 + 次のような GitLab CI/CD ジョブが失敗してしまった。

hoge:
@@ -153,11 +153,11 @@
   when: always

- grep コマンドは、パターンにマッチする行が一行もなかったとき、exit code 1 を返す。よって、pipefail が on になっていると、このジョブは失敗する。 現在の pipefail がどうなっているか確かめるため set +o で全オプションを出力させたところ、pipefail が on になっていた。 + grep コマンドは、パターンにマッチする行が一行もなかったとき、exit code 1 を返す。よって、pipefail が on になっていると、このジョブは失敗する。現在の pipefail がどうなっているか確かめるため set +o で全オプションを出力させたところ、pipefail が on になっていた。

- しかし、先述したように Bash における pipefail のデフォルト値は off のはずだ。 実際に、ローカルで alpine:latest を動かしてみたところ、 + しかし、先述したように Bash における pipefail のデフォルト値は off のはずだ。実際に、ローカルで alpine:latest を動かしてみたところ、

$ docker run --rm alpine:latest sh -c "set +o"
@@ -176,18 +176,18 @@ set +o vi
 set +o pipefail

- 確かに pipefail は無効になっている。 + 確かに pipefail は無効になっている。

- なぜスクリプト内で set -o pipefail しているわけでもないのに pipefail が on になっているのか。 + なぜスクリプト内で set -o pipefail しているわけでもないのに pipefail が on になっているのか。

どこで pipefail が on になるか

- .gitlab-ci.yml で明示的には書いていないので、GitLab Runner (GitLab CI/CD のスクリプトを実行するプログラム) が勝手に追加しているに違いない。 そう仮説を立てて GitLab Runner のリポジトリ を調査したところ、ソースコード中の以下の箇所set -o pipefail していることが判明した (コメントは筆者による)。 + .gitlab-ci.yml で明示的には書いていないので、GitLab Runner (GitLab CI/CD のスクリプトを実行するプログラム) が勝手に追加しているに違いない。そう仮説を立てて GitLab Runner のリポジトリ を調査したところ、ソースコード中の以下の箇所set -o pipefail していることが判明した (コメントは筆者による)。

// pipefail オプションが存在しない環境にも対応するため、
@@ -198,7 +198,7 @@ buf.WriteString("if set -o | grep pipefail > /
           

どのように解決するか

- 通常の Bash スクリプトを書く場合と同様に、pipefail が on になっていては困る場所だけ off にしてやればよい。 + 通常の Bash スクリプトを書く場合と同様に、pipefail が on になっていては困る場所だけ off にしてやればよい。

 hoge:
@@ -216,7 +216,7 @@ buf.WriteString("if set -o | grep pipefail > /
           

備考

- なお、上述した実装ファイルは shells/bash.go だが、alpine:latest の例でもそうであったように、シェルが sh である場合にも適用される。 + なお、上述した実装ファイルは shells/bash.go だが、alpine:latest の例でもそうであったように、シェルが sh である場合にも適用される。

diff --git a/vhosts/blog/public/posts/2024-04-29/zsh-file-completion-for-composer-custom-commands/index.html b/vhosts/blog/public/posts/2024-04-29/zsh-file-completion-for-composer-custom-commands/index.html index 8a9b3919..99216975 100644 --- a/vhosts/blog/public/posts/2024-04-29/zsh-file-completion-for-composer-custom-commands/index.html +++ b/vhosts/blog/public/posts/2024-04-29/zsh-file-completion-for-composer-custom-commands/index.html @@ -84,18 +84,18 @@

はじめに

- Composer は PHP のデファクトスタンダードなパッケージマネージャである。 Zsh では、composer コマンドに対する補完が提供されており、composer と入力してタブキーを押すと、利用可能なコマンドやオプションが補完される。 Zsh の補完はシェル関数の形で実装されており、composer コマンドに対応した補完をおこなうのは _composer である。 記事執筆時点での補完関数の定義は、GitHub のミラーリポジトリから参照できる。 + Composer は PHP のデファクトスタンダードなパッケージマネージャである。Zsh では、composer コマンドに対する補完が提供されており、composer と入力してタブキーを押すと、利用可能なコマンドやオプションが補完される。Zsh の補完はシェル関数の形で実装されており、composer コマンドに対応した補完をおこなうのは _composer である。記事執筆時点での補完関数の定義は、GitHub のミラーリポジトリから参照できる。

発生していた問題

- composer コマンドはカスタムコマンド (composer.jsonscripts で定義されたコマンド) に対して補完をおこなわない。 つまり、途中まで入力されたカスタムコマンドを補完しないし、カスタムコマンドの引数も補完しない。 例えば、PHPUnit を呼び出す phpunit というカスタムコマンドを定義し composer phpu まで打ってタブキーを押しても、composer phpunit にはならない。 また、composer phpunit -- -- まで打ってタブキーを押しても、phpunit コマンドのオプションは補完されない。 + composer コマンドはカスタムコマンド (composer.jsonscripts で定義されたコマンド) に対して補完をおこなわない。つまり、途中まで入力されたカスタムコマンドを補完しないし、カスタムコマンドの引数も補完しない。例えば、PHPUnit を呼び出す phpunit というカスタムコマンドを定義し composer phpu まで打ってタブキーを押しても、composer phpunit にはならない。また、composer phpunit -- -- まで打ってタブキーを押しても、phpunit コマンドのオプションは補完されない。

- このことは、先ほどリンクを載せた _composer 関数を定義しているファイルの冒頭にも書かれている。 + このことは、先ほどリンクを載せた _composer 関数を定義しているファイルの冒頭にも書かれている。

# - @todo We don't complete custom commands (including script aliases). This is
@@ -108,28 +108,28 @@
           

やりたいこと

- 確かに、カスタムコマンドに対して完全な補完を提供するのは不可能か、あるいは実現できても遅くなりすぎるだろう。 しかし、不完全なフォールバックを提供するくらいなら可能なはずだ。 + 確かに、カスタムコマンドに対して完全な補完を提供するのは不可能か、あるいは実現できても遅くなりすぎるだろう。しかし、不完全なフォールバックを提供するくらいなら可能なはずだ。

- この記事では、これらのカスタムコマンドについて、Zsh が提供するデフォルトのファイル・ディレクトリ補完を適用する。 つまり、composer phpunit -- tests/ まで打ってタブキーを押すと、tests ディレクトリの下にあるテストファイルまたはディレクトリが補完される。 + この記事では、これらのカスタムコマンドについて、Zsh が提供するデフォルトのファイル・ディレクトリ補完を適用する。つまり、composer phpunit -- tests/ まで打ってタブキーを押すと、tests ディレクトリの下にあるテストファイルまたはディレクトリが補完される。

解決策

- まずは、Zsh で補完関数を提供する場合のボイラープレートコードを書く。 以下は ~/.zshrc にすべて書く前提だが、autoload を設定するなどすれば別ファイルに分離できる (詳細な手順は割愛)。 + まずは、Zsh で補完関数を提供する場合のボイラープレートコードを書く。以下は ~/.zshrc にすべて書く前提だが、autoload を設定するなどすれば別ファイルに分離できる (詳細な手順は割愛)。

compdef _my_composer composer composer.phar

- compdef は Zsh が用意している関数で、第一引数に補完関数の名前、第二引数以降に補完を適用するコマンド名を並べる。 この場合は、composer コマンドや composer.phar コマンドに対して _my_composer を使って補完をおこなうよう定義している。 + compdef は Zsh が用意している関数で、第一引数に補完関数の名前、第二引数以降に補完を適用するコマンド名を並べる。この場合は、composer コマンドや composer.phar コマンドに対して _my_composer を使って補完をおこなうよう定義している。

- 次に _my_composer を定義する。基本的にはデフォルトの composer コマンドの補完関数 (つまり _composer 関数) を使い、それが何も返さなかった場合に限り、Zsh のファイル・ディレクトリ補完へフォールバックする。 + 次に _my_composer を定義する。基本的にはデフォルトの composer コマンドの補完関数 (つまり _composer 関数) を使い、それが何も返さなかった場合に限り、Zsh のファイル・ディレクトリ補完へフォールバックする。

function _my_composer() {
@@ -137,14 +137,14 @@
 }

- _composer コマンドは何も補完候補がなかったとき非ゼロな exit status で終了するので、そうであったなら _files を呼び出す。 _files は、Zsh がデフォルトで用意しているファイル・ディレクトリの補完をおこなう関数である。 + _composer コマンドは何も補完候補がなかったとき非ゼロな exit status で終了するので、そうであったなら _files を呼び出す。_files は、Zsh がデフォルトで用意しているファイル・ディレクトリの補完をおこなう関数である。

まとめ

- これらの設定をおこなうことで、部分的ながら Composer のカスタムコマンドに対して補完をおこなうことができる。 特に、PHPUnit や PHPStan などの対象ファイル・ディレクトリを引数に取るようなコマンドを使う場合に有用であろう。 + これらの設定をおこなうことで、部分的ながら Composer のカスタムコマンドに対して補完をおこなうことができる。特に、PHPUnit や PHPStan などの対象ファイル・ディレクトリを引数に取るようなコマンドを使う場合に有用であろう。

diff --git a/vhosts/blog/public/posts/2024-05-11/phpconkagawa-2024-report/index.html b/vhosts/blog/public/posts/2024-05-11/phpconkagawa-2024-report/index.html index b651f5b3..e3f53399 100644 --- a/vhosts/blog/public/posts/2024-05-11/phpconkagawa-2024-report/index.html +++ b/vhosts/blog/public/posts/2024-05-11/phpconkagawa-2024-report/index.html @@ -67,7 +67,7 @@

はじめに

- 2024-05-11 に開催された PHP カンファレンス香川 2024 に参加した。 + 2024-05-11 に開催された PHP カンファレンス香川 2024 に参加した。

@@ -82,7 +82,7 @@
  • - 感想: ちょうどとあるマイグレーション作業をしているので、頷きながら拝聴しました。結局は誰しも移行作業は根気と腕力なのだということに勇気をもらえました。 + 感想: ちょうどとあるマイグレーション作業をしているので、頷きながら拝聴しました。結局は誰しも移行作業は根気と腕力なのだということに勇気をもらえました。
  • @@ -95,7 +95,7 @@
  • - 感想: これも上と同じく移行作業の話ではあり、結局のところは「頑張って地道にやっていく」しかないところもあります (とはいえこちらは静的解析である程度潰せますが)。PHP 言語のコミュニティ全体で頑張っていきましょう。 + 感想: これも上と同じく移行作業の話ではあり、結局のところは「頑張って地道にやっていく」しかないところもあります (とはいえこちらは静的解析である程度潰せますが)。PHP 言語のコミュニティ全体で頑張っていきましょう。
  • @@ -108,7 +108,7 @@
  • - 感想: 今会社でペアプロを部分的に取り入れているものの、迷うところが多く、楽しみにしていた発表です。まずは何か一つ変えないことには始まらないので、発表から得たヒントを自分たちのチームに反映すべく、何かやりかたを変えてみる予定です。 + 感想: 今会社でペアプロを部分的に取り入れているものの、迷うところが多く、楽しみにしていた発表です。まずは何か一つ変えないことには始まらないので、発表から得たヒントを自分たちのチームに反映すべく、何かやりかたを変えてみる予定です。
  • @@ -121,7 +121,7 @@
  • - 感想: RFC を必要とするような機能追加のプロセスを日本語で解説する資料がどんどんと増えていくのは、ハードルを下げるという意味で非常にありがたいです。私も以前から出そう出そうと考えている書きかけの RFC があるのですが、具体的なプロセスが明示されるとやはりやる気になりますね。 + 感想: RFC を必要とするような機能追加のプロセスを日本語で解説する資料がどんどんと増えていくのは、ハードルを下げるという意味で非常にありがたいです。私も以前から出そう出そうと考えている書きかけの RFC があるのですが、具体的なプロセスが明示されるとやはりやる気になりますね。
  • @@ -134,11 +134,11 @@
  • - 備考: ちょっとしたトラブルにより午前中の発表が見られなかったので、生で拝聴したわけではなく、スライドを拝見して感想を書いています。 + 備考: ちょっとしたトラブルにより午前中の発表が見られなかったので、生で拝聴したわけではなく、スライドを拝見して感想を書いています。
  • - 感想: Thanks のスライド非常に嬉しかったです。こちらこそ素晴らしいカンファレンスの場をありがとうございました!スタッフ募集あれば来年も是非参加させてください。 + 感想: Thanks のスライド非常に嬉しかったです。こちらこそ素晴らしいカンファレンスの場をありがとうございました!スタッフ募集あれば来年も是非参加させてください。
  • @@ -148,26 +148,26 @@

    懇親会 LT

    - 今回登壇者ではなかったのだが、プロポーザル募集時に用意していたスライド (LT 用に作っていたのだが、そもそも LT 枠がなかったのでお蔵入りになっていた) があったので懇親会の LT で発表した。 + 今回登壇者ではなかったのだが、プロポーザル募集時に用意していたスライド (LT 用に作っていたのだが、そもそも LT 枠がなかったのでお蔵入りになっていた) があったので懇親会の LT で発表した。

    - 中身は第150回PHP勉強会@東京で登壇した内容とほぼ同じで、タイトルを「うどんのように細長い FizzBuzz を書く」にしただけの手抜き・一発ネタ発表である。個別にスライドはアップロードしないので、前述のリンクを参照してほしい。 + 中身は第150回PHP勉強会@東京で登壇した内容とほぼ同じで、タイトルを「うどんのように細長い FizzBuzz を書く」にしただけの手抜き・一発ネタ発表である。個別にスライドはアップロードしないので、前述のリンクを参照してほしい。

    - なお、この発表にはブログ記事バージョンもある。 + なお、この発表にはブログ記事バージョンもある。

    おわりに

    - 午前中の発表に間に合わなかったことがとにかく心残りなのだが、それ以外は PHP カンファレンス小田原のスタッフの方々をはじめ多くの方と交流でき、非常に楽しいカンファレンスだった。来年もあるそうなので (この分だと来年も月刊 PHP カンファレンスにならないか?)、是非参加したい。 + 午前中の発表に間に合わなかったことがとにかく心残りなのだが、それ以外は PHP カンファレンス小田原のスタッフの方々をはじめ多くの方と交流でき、非常に楽しいカンファレンスだった。来年もあるそうなので (この分だと来年も月刊 PHP カンファレンスにならないか?)、是非参加したい。

    - あれ、そういえば香川でうどん食べてないな......。 + あれ、そういえば香川でうどん食べてないな......。

    diff --git a/vhosts/blog/public/posts/2024-06-19/scalamatsuri-2024-report/index.html b/vhosts/blog/public/posts/2024-06-19/scalamatsuri-2024-report/index.html index 1461147e..d5444b32 100644 --- a/vhosts/blog/public/posts/2024-06-19/scalamatsuri-2024-report/index.html +++ b/vhosts/blog/public/posts/2024-06-19/scalamatsuri-2024-report/index.html @@ -67,32 +67,32 @@

    はじめに

    - 2024-06-08 から 2024-06-09 にかけて開催された ScalaMatsuri 2024 に参加した。 + 2024-06-08 から 2024-06-09 にかけて開催された ScalaMatsuri 2024 に参加した。

    - Day 2 には当日参加できなかったため、day 2 のセッションの感想は YouTube にアップロードされたアーカイブ動画を観て書いている。 + Day 2 には当日参加できなかったため、day 2 のセッションの感想は YouTube にアップロードされたアーカイブ動画を観て書いている。

    セッション感想

    - 特に印象に残ったセッションを、day 1 と day 2 で一つずつ選んだ (タイトルと登壇者名は 公式ホームページの「プログラム」 から引用)。 + 特に印象に残ったセッションを、day 1 と day 2 で一つずつ選んだ (タイトルと登壇者名は 公式ホームページの「プログラム」 から引用)。

    • Scala to WebAssembly: 動機と方法 (Rikito Taniguchi さん)
        - 最近 WebAssembly の処理系を作った こともあって、気になっていたセッションです。私の処理系は WasmGC proposal を実装していないので動かせないのですが、いつかサポートして動かしてみたいですね。 + 最近 WebAssembly の処理系を作った こともあって、気になっていたセッションです。私の処理系は WasmGC proposal を実装していないので動かせないのですが、いつかサポートして動かしてみたいですね。
    • 作って学ぶ Extensible Effects (Kory さん・hsjoihs さん)
        - 今回一番楽しみにしていたセッションです。Day 2 当日は参加できず、後日アーカイブ動画を視聴したのですが、期待を裏切らない濃厚なセッションでした。後日開かれた NB-Scala レトロスペクティブ (非公式後夜祭) の発表も拝聴したのですが、どちらも非常に面白かったです。 + 今回一番楽しみにしていたセッションです。Day 2 当日は参加できず、後日アーカイブ動画を視聴したのですが、期待を裏切らない濃厚なセッションでした。後日開かれた NB-Scala レトロスペクティブ (非公式後夜祭) の発表も拝聴したのですが、どちらも非常に面白かったです。
    @@ -114,11 +114,11 @@

    おわりに

    - 私が Scala を書いたり追ったりしていたのは Scala 2 の頃で、Scala 3 はほとんど浦島太郎状態だったのだが、非常に楽しく面白いイベントだった。 イベントに触発されて、長らく塩漬けになっていた Scala 製の趣味プロジェクトを久しぶりに触っているのだが、これもまた楽しい。 + 私が Scala を書いたり追ったりしていたのは Scala 2 の頃で、Scala 3 はほとんど浦島太郎状態だったのだが、非常に楽しく面白いイベントだった。イベントに触発されて、長らく塩漬けになっていた Scala 製の趣味プロジェクトを久しぶりに触っているのだが、これもまた楽しい。

    - ScalaMatsuri 運営の皆さま、スピーカーの皆さま、スポンサーの皆さま、最高のイベントをありがとうございました!次回も楽しみにしています。 + ScalaMatsuri 運営の皆さま、スピーカーの皆さま、スポンサーの皆さま、最高のイベントをありがとうございました!次回も楽しみにしています。

    diff --git a/vhosts/blog/public/posts/2024-07-19/reparojson-fix-only-json-formatter/index.html b/vhosts/blog/public/posts/2024-07-19/reparojson-fix-only-json-formatter/index.html index 785aae33..c5724274 100644 --- a/vhosts/blog/public/posts/2024-07-19/reparojson-fix-only-json-formatter/index.html +++ b/vhosts/blog/public/posts/2024-07-19/reparojson-fix-only-json-formatter/index.html @@ -66,18 +66,18 @@ NOTE
    - この記事は Vim 駅伝 #218 の記事です。 + この記事は Vim 駅伝 #218 の記事です。

    欲しかったもの

    - Vim で JSON を編集しているときに、文法エラー (末尾カンマやカンマの不足) のみを修正して一切の整形をおこなわないプラグインが欲しかった。 整形も同時におこなうプラグインは見つかっただけでも多数あったのだが、整形しないものは見つけられなかったので自作することにした。 + Vim で JSON を編集しているときに、文法エラー (末尾カンマやカンマの不足) のみを修正して一切の整形をおこなわないプラグインが欲しかった。整形も同時におこなうプラグインは見つかっただけでも多数あったのだが、整形しないものは見つけられなかったので自作することにした。

    - なお、作成したツール自体は単体の CLI として動作し、Vim とは無関係に使うことができる。 この記事では Neovim と組み合わせる場合の設定を紹介するが、およそ任意のエディタで使えるだろう。 + なお、作成したツール自体は単体の CLI として動作し、Vim とは無関係に使うことができる。この記事では Neovim と組み合わせる場合の設定を紹介するが、およそ任意のエディタで使えるだろう。

    @@ -88,7 +88,7 @@

    - 次のように動作する。 + 次のように動作する。

    $ echo '[ 1 2 ]' | reparojson
    @@ -126,18 +126,18 @@ $ echo '{ "foo": 1, "bar": 2, }' | reparojson
                 
                  
                 

    - 他にも自動で直せそうなエラーはいくつか思いつくが (オブジェクトのキーがクォートされていない等)、私自身があまり困っていないので優先度は低い。 + 他にも自動で直せそうなエラーはいくつか思いつくが (オブジェクトのキーがクォートされていない等)、私自身があまり困っていないので優先度は低い。

    Neovim との連携

    - Neovim で JSON ファイルを保存したときに、上記のツールを自動で走らせるように設定する。 + Neovim で JSON ファイルを保存したときに、上記のツールを自動で走らせるように設定する。

    - ここでは、nvim-lspconfigefm-langserver を用いた設定例を紹介する。 + ここでは、nvim-lspconfigefm-langserver を用いた設定例を紹介する。

    local lspconfig = require('lspconfig')
    @@ -169,14 +169,14 @@ vim.api.nvim_create_autocmd('LspAttach'

    - ほとんどは nvim-lspconfig と efm-langserver を使う際のボイラープレートだが、formatCommand-q フラグを指定していることに注意してほしい。 このツールは、デフォルトでは JSON が修正された場合 exit code 1 で終了する。 これは、入力が最初から正しかった場合と修正して正しくなった場合を区別するためだが、異常終了してしまうと置き換えが発生しない。 そのため、-q フラグを指定して、修正されたときも exit code 0 で終了するようにしている。 + ほとんどは nvim-lspconfig と efm-langserver を使う際のボイラープレートだが、formatCommand-q フラグを指定していることに注意してほしい。このツールは、デフォルトでは JSON が修正された場合 exit code 1 で終了する。これは、入力が最初から正しかった場合と修正して正しくなった場合を区別するためだが、異常終了してしまうと置き換えが発生しない。そのため、-q フラグを指定して、修正されたときも exit code 0 で終了するようにしている。

    おわりに

    - このツールが威力を発揮するのは、行の入れ換え時である。次のような JSON があり、 + このツールが威力を発揮するのは、行の入れ換え時である。次のような JSON があり、

    {
    @@ -185,7 +185,7 @@ vim.api.nvim_create_autocmd('LspAttach'}

    - 2行目と3行目を入れ換えて以下のように編集した。 + 2行目と3行目を入れ換えて以下のように編集した。

    {
    @@ -194,7 +194,7 @@ vim.api.nvim_create_autocmd('LspAttach'}

    - これは不正な JSON だが、このツールを通せば次のようになる。 + これは不正な JSON だが、このツールを通せば次のようになる。

    {
    @@ -203,7 +203,7 @@ vim.api.nvim_create_autocmd('LspAttach'}

    - もちろん、このような操作を文法を壊さずにおこなう Vim プラグインは存在する。 しかし、単なる行の入れ換えであれば ddp の3ストロークでおこなうことができ、専用のキーバインドを覚える必要もない。 このツールを用いることで、より Vimmer-friendly な JSON 編集が可能となる。 + もちろん、このような操作を文法を壊さずにおこなう Vim プラグインは存在する。しかし、単なる行の入れ換えであれば ddp の3ストロークでおこなうことができ、専用のキーバインドを覚える必要もない。このツールを用いることで、より Vimmer-friendly な JSON 編集が可能となる。

    diff --git a/vhosts/blog/public/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html b/vhosts/blog/public/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html index 9abb2e7b..2d2c3761 100644 --- a/vhosts/blog/public/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html +++ b/vhosts/blog/public/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html @@ -61,14 +61,14 @@

    TL;DR

    - 常にトップレベルを指す特殊変数 $ を使えばよい。 + 常にトップレベルを指す特殊変数 $ を使えばよい。

    はじめに

    - Go には、標準ライブラリにテンプレートライブラリ text/template がある。 この text/template における制御構造、withrange は次のように使われる。 + Go には、標準ライブラリにテンプレートライブラリ text/template がある。この text/template における制御構造、withrange は次のように使われる。

    # {{ .Title }}
    @@ -86,15 +86,15 @@
     {{ end }}

    - text/template. は、現在の操作対象を表す特殊なオブジェクトである。 + text/template. は、現在の操作対象を表す特殊なオブジェクトである。

    - withrange は、. を変更する効果を持つ。 with は引数に渡されたオブジェクトを . へセットして、内部のテンプレートを実行する。 range は引数に渡されたイテレート可能なオブジェクトに対し、それぞれの要素を . へセットして、要素の個数だけ内部のテンプレートを実行する。 + withrange は、. を変更する効果を持つ。with は引数に渡されたオブジェクトを . へセットして、内部のテンプレートを実行する。range は引数に渡されたイテレート可能なオブジェクトに対し、それぞれの要素を . へセットして、要素の個数だけ内部のテンプレートを実行する。

    - つまりこのテンプレートは、次のような構造をレンダリングしている (Execute() の第2引数)。 + つまりこのテンプレートは、次のような構造をレンダリングしている (Execute() の第2引数)。

    tmpl.Execute(out, Params{
    @@ -114,7 +114,7 @@
               

    やりたいこと

    - 今回おこないたいのは、withrange の中で、その外側で使われていたトップレベルのオブジェクトを参照することだ。 + 今回おこないたいのは、withrange の中で、その外側で使われていたトップレベルのオブジェクトを参照することだ。

    {{ with .User }}
    @@ -126,7 +126,7 @@
     {{ end }}

    - withrange は、. を自身の対象オブジェクトに変更するので、 単に {{ with .User }} の中で .Title と書いても、それは UserTitle プロパティを参照しているとみなされる。 + withrange は、. を自身の対象オブジェクトに変更するので、単に {{ with .User }} の中で .Title と書いても、それは UserTitle プロパティを参照しているとみなされる。

    @@ -136,18 +136,18 @@

    {{ $params := . }}

    - とでもしておけば実現は可能である。 + とでもしておけば実現は可能である。

    - しかしながら、頻発するシチュエーションにしてはあまりに不恰好である。よりスマートな方法が用意されているはずだ。 + しかしながら、頻発するシチュエーションにしてはあまりに不恰好である。よりスマートな方法が用意されているはずだ。

    解決方法

    - 常にトップレベルを指す特殊変数 $ を使えばよい。 + 常にトップレベルを指す特殊変数 $ を使えばよい。

    {{ with .User }}
    @@ -159,11 +159,11 @@
     {{ end }}

    - $ は、テンプレートが実行されるときに渡されたオブジェクトを指す。 これを使えば現在の . に関係なくトップレベルを参照できる。 + $ は、テンプレートが実行されるときに渡されたオブジェクトを指す。これを使えば現在の . に関係なくトップレベルを参照できる。

    - このことは、text/template の公式ドキュメントにも以下のように記載されている。 + このことは、text/template の公式ドキュメントにも以下のように記載されている。

    diff --git a/vhosts/blog/public/posts/2024-09-28/mncore-challenge-1/index.html b/vhosts/blog/public/posts/2024-09-28/mncore-challenge-1/index.html index bd71abce..640f0af8 100644 --- a/vhosts/blog/public/posts/2024-09-28/mncore-challenge-1/index.html +++ b/vhosts/blog/public/posts/2024-09-28/mncore-challenge-1/index.html @@ -63,33 +63,33 @@ NOTE
    - ただの参加記で解説はない。 + ただの参加記で解説はない。

    はじめに

    - 2024-08-28 から 2024-09-24 の約1ヶ月に渡り開催された MN-Core Challenge #1 に参加した。私 nsfisis (あるいは 0b0100000111111000) はスコア 1181 で、最終順位 29 位だった。 + 2024-08-28 から 2024-09-24 の約1ヶ月に渡り開催された MN-Core Challenge #1 に参加した。私 nsfisis (あるいは 0b0100000111111000) はスコア 1181 で、最終順位 29 位だった。

    - この記事で解説はしないが、提出した回答はこちらのリポジトリ (GitHub: nsfisis/mncore-challenge) にアップロードしている。 + この記事で解説はしないが、提出した回答はこちらのリポジトリ (GitHub: nsfisis/mncore-challenge) にアップロードしている。

    感想

    - MN-Core には初めて触れたが、それでも問題なく全問 (除 FizzBuzz) 解けるよう線路が敷かれており、前半の問題を解くことで自然と後半を解くだけの知識が身に付くように設計されていた。 + MN-Core には初めて触れたが、それでも問題なく全問 (除 FizzBuzz) 解けるよう線路が敷かれており、前半の問題を解くことで自然と後半を解くだけの知識が身に付くように設計されていた。

    - 開催期間中はほぼ常に MN-Core Challenge のことを考え続けており、期間中 (前掲した回答を貯めるためのリポジトリを除き) 自分の Git リポジトリをほとんど触ることがなかった。途中更新ができずに苦しい時間もあったが、一つ気付くと一つ縮まる楽しいゴルフだった。 + 開催期間中はほぼ常に MN-Core Challenge のことを考え続けており、期間中 (前掲した回答を貯めるためのリポジトリを除き) 自分の Git リポジトリをほとんど触ることがなかった。途中更新ができずに苦しい時間もあったが、一つ気付くと一つ縮まる楽しいゴルフだった。

    - 悔しいポイントも多数あるのだが、書いているとキリがないので自分で反省するだけにしておく。 + 悔しいポイントも多数あるのだが、書いているとキリがないので自分で反省するだけにしておく。

    diff --git a/vhosts/blog/public/posts/2024-12-04/cohackpp-report/index.html b/vhosts/blog/public/posts/2024-12-04/cohackpp-report/index.html index 0d0aff8d..f98a752d 100644 --- a/vhosts/blog/public/posts/2024-12-04/cohackpp-report/index.html +++ b/vhosts/blog/public/posts/2024-12-04/cohackpp-report/index.html @@ -67,16 +67,16 @@

    はじめに

    - 2024-11-30 に開催された紅白ぺぱ合戦なる催しに参加しました。私は「ぺ」陣営のメンバとして LT をおこないました。 + 2024-11-30 に開催された紅白ぺぱ合戦なる催しに参加しました。私は「ぺ」陣営のメンバとして LT をおこないました。

    - 紅白ぺぱ合戦のイベントページにある説明を以下に引用します。 + 紅白ぺぱ合戦のイベントページにある説明を以下に引用します。

    - WebエンジニアのasumikamとWebエンジニアのstefafafanが2024年7月7日に結婚しました。 + WebエンジニアのasumikamとWebエンジニアのstefafafanが2024年7月7日に結婚しました。

    @@ -89,18 +89,18 @@

    - ざっくりと言えば、テックカンファレンスの形式をとった結婚披露宴です。タイトルの「ぺ」は PHPer、「ぱ」は Perl Monger の略です。 + ざっくりと言えば、テックカンファレンスの形式をとった結婚披露宴です。タイトルの「ぺ」は PHPer、「ぱ」は Perl Monger の略です。

    感想

    - 私は「ぺ」陣営のスピーカーとして LT をしていたのですが、その前にまずは登壇以外の感想を。 + 私は「ぺ」陣営のスピーカーとして LT をしていたのですが、その前にまずは登壇以外の感想を。

    - いや~最高でしたね。どの枠のスピーチの方も良かったのですが、特に (asumikam さん/stefafafan さんに)「育てられた」枠のお二方が印象に残っています。 (asumikam さん/stefafafan さんを)「育てた」枠としてお世話になった方に声をかけることはできると思うんですよ。 それだけでなく、「自分が育てたのだ」と言える人がいて、そしてそれに 100 点で応える人がいるということ。この素晴しさ。人徳。 + いや~最高でしたね。どの枠のスピーチの方も良かったのですが、特に (asumikam さん/stefafafan さんに)「育てられた」枠のお二方が印象に残っています。(asumikam さん/stefafafan さんを)「育てた」枠としてお世話になった方に声をかけることはできると思うんですよ。それだけでなく、「自分が育てたのだ」と言える人がいて、そしてそれに 100 点で応える人がいるということ。この素晴しさ。人徳。

    @@ -113,29 +113,29 @@

    合戦準備

    - さて、時を合戦の前に戻しまして、両陣営の登壇者が発表され徐々に謎のイベントの輪郭が見えてきた頃、asumikam さんから次のような連絡を受けました。 + さて、時を合戦の前に戻しまして、両陣営の登壇者が発表され徐々に謎のイベントの輪郭が見えてきた頃、asumikam さんから次のような連絡を受けました。

    asumikam「いまむらさんおつかれさまです。ぺぱ合戦で、LTタイムあることになり、技術で3人「ぺ」側を選出することになったのですが、いまむらさん、LTやりませんか。「ぺ」陣営で一緒に頂きを目指しませんか。」nsfisis「OKです!」

    - 最初は直近のカンファレンスに出して落選したプロポーザルテーマを LT に編集して話そうとしていたのですが、この機会でなければ話せない・この機会で話すことに意味があるテーマにしようとネタ出しをおこない、最終的に次のテーマでの登壇となりました。 + 最初は直近のカンファレンスに出して落選したプロポーザルテーマを LT に編集して話そうとしていたのですが、この機会でなければ話せない・この機会で話すことに意味があるテーマにしようとネタ出しをおこない、最終的に次のテーマでの登壇となりました。

    いざ尋常に勝負

    - 当日は、「プログラミングマナー講座」と題して発表をおこないました。 結婚式のマナー、特に「忌み言葉」へフォーカスし、これを無理やりプログラミングに適用するというものです。 スライドはこちらにアップロードしています。 + 当日は、「プログラミングマナー講座」と題して発表をおこないました。結婚式のマナー、特に「忌み言葉」へフォーカスし、これを無理やりプログラミングに適用するというものです。スライドはこちらにアップロードしています。

    - 最終的にお祝いのメッセージを仕込んだソースコードで締めるという構成は、我ながら綺麗にまとまったと思っています。忌み言葉の案は他にも大量にあったのですが、技術 LT かつ結婚祝いスピーチにするためにどうしても最後のソースコードが必要だったので、時間の関係上それらには犠牲となってもらいました (ボツになった案のひとつ)。 + 最終的にお祝いのメッセージを仕込んだソースコードで締めるという構成は、我ながら綺麗にまとまったと思っています。忌み言葉の案は他にも大量にあったのですが、技術 LT かつ結婚祝いスピーチにするためにどうしても最後のソースコードが必要だったので、時間の関係上それらには犠牲となってもらいました (ボツになった案のひとつ)。

    - そもそも結婚式・披露宴でのスピーチ自体が初めてだったのでそれなりに緊張していたのですが、登壇時やその後の反応を伺う限り概ね好評だったようで良かったです。 + そもそも結婚式・披露宴でのスピーチ自体が初めてだったのでそれなりに緊張していたのですが、登壇時やその後の反応を伺う限り概ね好評だったようで良かったです。

    diff --git a/vhosts/blog/public/posts/2024-12-33/2024-reflections/index.html b/vhosts/blog/public/posts/2024-12-33/2024-reflections/index.html index 5b2e51ac..f2169b2c 100644 --- a/vhosts/blog/public/posts/2024-12-33/2024-reflections/index.html +++ b/vhosts/blog/public/posts/2024-12-33/2024-reflections/index.html @@ -55,7 +55,7 @@

    はじめに

    - ご存じのとおり、4 と 11 と 23 で割り切れる年は閏年というやつで 12 月が 33 日まである。 1年の振り返りを書く猶予が平年よりも長くなるので大変に都合がよい。 + ご存じのとおり、4 と 11 と 23 で割り切れる年は閏年というやつで 12 月が 33 日まである。1年の振り返りを書く猶予が平年よりも長くなるので大変に都合がよい。

    @@ -66,7 +66,7 @@

    登壇・カンファレンス参加

    - 参加または登壇した勉強会やカンファレンス。 LT 等も含めて計 8 回の登壇をおこなった。 また、4つのカンファレンスでコアスタッフまたは当日スタッフとして参加した。 + 参加または登壇した勉強会やカンファレンス。LT 等も含めて計 8 回の登壇をおこなった。また、4つのカンファレンスでコアスタッフまたは当日スタッフとして参加した。

      @@ -157,7 +157,7 @@

      書いた記事

      - 今年はこのブログに月1記事以上の記事を書くという目標を立てていた。本数としては 12 本以上あるが、10月と11月はゼロになってしまった。 社内記事を社外向けにリライトする作業を中々進められていないので、2025年は定期的に消化していきたい。 + 今年はこのブログに月1記事以上の記事を書くという目標を立てていた。本数としては 12 本以上あるが、10月と11月はゼロになってしまった。社内記事を社外向けにリライトする作業を中々進められていないので、2025年は定期的に消化していきたい。

        @@ -179,7 +179,7 @@

        作ったもの

        - 今年は主に WebAssembly ランタイムと、カンファレンスの企画で使うシステムを作っていた。 後者のシステムでもサンドボックス化のための技術として WebAssembly を用いているので、今年は WebAssembly と戯れた一年だったと言える。 + 今年は主に WebAssembly ランタイムと、カンファレンスの企画で使うシステムを作っていた。後者のシステムでもサンドボックス化のための技術として WebAssembly を用いているので、今年は WebAssembly と戯れた一年だったと言える。

          diff --git a/vhosts/blog/public/posts/2025-01-08/phperkaigi-2023-tokens-q1/index.html b/vhosts/blog/public/posts/2025-01-08/phperkaigi-2023-tokens-q1/index.html index c76dd5fa..16bf6730 100644 --- a/vhosts/blog/public/posts/2025-01-08/phperkaigi-2023-tokens-q1/index.html +++ b/vhosts/blog/public/posts/2025-01-08/phperkaigi-2023-tokens-q1/index.html @@ -77,20 +77,20 @@ NOTE
          - これは PHPerKaigi 2023 の記事です。今は 2025 年ですが、PHPerKaigi 2023 の記事です。 + これは PHPerKaigi 2023 の記事です。今は 2025 年ですが、PHPerKaigi 2023 の記事です。

          - 2023-03-23 から 2023-03-25 にかけて開催された PHPerKaigi 2023 では、PHPer チャレンジという企画がおこなわれた。 PHPer チャレンジとは、スポンサーのパンフレットやカンファレンス会場などから「#」記号で始まる文字列を集め、景品などを得るという企画である。 この文字列は「PHPer トークン」と呼ばれている。弊社デジタルサーカス株式会社からは、トークン問題という形で、PHP に関する問題を解くと PHPer トークンが得られるようになっている問題を出題した。 + 2023-03-23 から 2023-03-25 にかけて開催された PHPerKaigi 2023 では、PHPer チャレンジという企画がおこなわれた。PHPer チャレンジとは、スポンサーのパンフレットやカンファレンス会場などから「#」記号で始まる文字列を集め、景品などを得るという企画である。この文字列は「PHPer トークン」と呼ばれている。弊社デジタルサーカス株式会社からは、トークン問題という形で、PHP に関する問題を解くと PHPer トークンが得られるようになっている問題を出題した。

          - PHPerKaigi 2023 の参加レポ でも書いたとおり、この年のトークン問題は「昨年の PHPerKaigi 2022 が終わった段階から作り始め、約半年かけて制作」された。 PHPerKaigi 当日も PHPer チャレンジ解説セッション という形で解説の機会を頂いたのだが、せっかく時間をかけて作題したので記事の形でも残しておこうと思う。 + PHPerKaigi 2023 の参加レポ でも書いたとおり、この年のトークン問題は「昨年の PHPerKaigi 2022 が終わった段階から作り始め、約半年かけて制作」された。PHPerKaigi 当日も PHPer チャレンジ解説セッション という形で解説の機会を頂いたのだが、せっかく時間をかけて作題したので記事の形でも残しておこうと思う。

          - この記事では、全5問ある中の第1問について解説する。他の問題については以下のリンクを参照のこと。 + この記事では、全5問ある中の第1問について解説する。他の問題については以下のリンクを参照のこと。

            @@ -116,14 +116,14 @@

          - それぞれの問題はこちらの GitHub リポジトリ (nsfisis/PHPerKaigi2023-tokens) からも閲覧できる。 + それぞれの問題はこちらの GitHub リポジトリ (nsfisis/PHPerKaigi2023-tokens) からも閲覧できる。

        Q1: An Art of Computer Programming

        - 第1問『An Art of Computer Programming』はこちら。 + 第1問『An Art of Computer Programming』はこちら。

        全体がQRコードになっており、中央には小さな文字で「Password is one of the PHPer tokens.」と書かれている @@ -133,13 +133,13 @@

        解き方

        - まずはトークンを得る方法を解説抜きで説明する。次のように実行する。 + まずはトークンを得る方法を解説抜きで説明する。次のように実行する。

        $ echo "#iwillblog" | php Q1.png >/dev/null

        - 無事に実行できていれば「#ModernPHPisStaticallyTypedLanguage」というトークンが得られる。 + 無事に実行できていれば「#ModernPHPisStaticallyTypedLanguage」というトークンが得られる。

        @@ -148,50 +148,50 @@

        画像として解釈する

        - まずは素直に画像として見てみよう。 全体は QR コードになっている。適当な QR コードリーダで読み込むと、次のようなテキストが表示されるはずだ。 + まずは素直に画像として見てみよう。全体は QR コードになっている。適当な QR コードリーダで読み込むと、次のようなテキストが表示されるはずだ。

        Guess password. $ echo "password" | php Q1.png >/dev/null

        - メッセージは、この画像の実行方法とこの問題でやるべきこと (パスワードの推測) を示している。 + メッセージは、この画像の実行方法とこの問題でやるべきこと (パスワードの推測) を示している。

        - 次に QR コードの中央部に目を向けると、小さな文字で「Password is one of the PHPer tokens.」と書かれているのがわかる。 他の PHPer トークンの中から適切な1つを見つけだし、「パスワード」として渡すことで答えとなる PHPer トークンが得られるというわけだ。 + 次に QR コードの中央部に目を向けると、小さな文字で「Password is one of the PHPer tokens.」と書かれているのがわかる。他の PHPer トークンの中から適切な1つを見つけだし、「パスワード」として渡すことで答えとなる PHPer トークンが得られるというわけだ。

        パスワード

        - 不正なパスワードを使って実行してみると、次のようなエラーメッセージが表示される。 + 不正なパスワードを使って実行してみると、次のようなエラーメッセージが表示される。

        $ echo "foo" | php Q1.png >/dev/null
         401 Unauthorized

        - すでに「解き方」の節で示したように、パスワードである PHPer トークンは「#iwillblog」である。これを与えて実行すると正解のトークンが得られる。 + すでに「解き方」の節で示したように、パスワードである PHPer トークンは「#iwillblog」である。これを与えて実行すると正解のトークンが得られる。

        - このパスワードの選択にはとある事情がある。 今回の問題の作問は前回の開催 (PHPerKaigi 2022) 直後からスタートしており、この時点では PHPerKaigi 2023 で登録される PHPer トークンにどのようなものがあるかはまったくわからない状態であった。 作問作業を早期に終わらせるには、次回開催でも確実に使われるであろう定番のトークンを予測して選ぶ必要があったのだ。 かくして、私が知る限り毎回登場しているトークンである「#iwillblog」に白羽の矢が立てられた。 + このパスワードの選択にはとある事情がある。今回の問題の作問は前回の開催 (PHPerKaigi 2022) 直後からスタートしており、この時点では PHPerKaigi 2023 で登録される PHPer トークンにどのようなものがあるかはまったくわからない状態であった。作問作業を早期に終わらせるには、次回開催でも確実に使われるであろう定番のトークンを予測して選ぶ必要があったのだ。かくして、私が知る限り毎回登場しているトークンである「#iwillblog」に白羽の矢が立てられた。

        - なお、解いてくださった方の中には、先頭の「#」を入力せずに何度も試してしまい答えが得られずじまいになった方もいらっしゃるようだった。 問題を置いていたリポジトリにヒントとしてパスワードのトークンが「i」で始まると書いていたのだが、これが意図せずミスリードになってしまった。 これは私のミスである。 + なお、解いてくださった方の中には、先頭の「#」を入力せずに何度も試してしまい答えが得られずじまいになった方もいらっしゃるようだった。問題を置いていたリポジトリにヒントとしてパスワードのトークンが「i」で始まると書いていたのだが、これが意図せずミスリードになってしまった。これは私のミスである。

        PNG ステガノグラフィ

        - QR コードも言っているように、このファイルは PNG 画像であるにもかかわらず PHP で実行することができる。なぜこのようなことが可能なのか。 + QR コードも言っているように、このファイルは PNG 画像であるにもかかわらず PHP で実行することができる。なぜこのようなことが可能なのか。

        - PNG 画像のフォーマットは、次のようになっている。 + PNG 画像のフォーマットは、次のようになっている。

          @@ -213,15 +213,15 @@

        - PNG フッタの後ろにあるデータは、画像ビューアには解釈されず、画像の表示には影響を与えない。したがって、PNG フッタの後ろには任意のデータを埋め込むことができる。 + PNG フッタの後ろにあるデータは、画像ビューアには解釈されず、画像の表示には影響を与えない。したがって、PNG フッタの後ろには任意のデータを埋め込むことができる。

        - さて、PHP には、PHP プログラムの始まりを示すための PHP タグ (<?php または <?) がある。 CLI で実行する場合、PHP タグよりも前にあるデータは標準出力へそのまま出力される。 + さて、PHP には、PHP プログラムの始まりを示すための PHP タグ (<?php または <?) がある。CLI で実行する場合、PHP タグよりも前にあるデータは標準出力へそのまま出力される。

        - この画像ファイルは次のような構造になっていた。 + この画像ファイルは次のような構造になっていた。

          @@ -251,11 +251,11 @@

        - PNG ファイルとして読むときは PNG フッタ以降は無視され、PHP スクリプトとして読むときは PHP タグ以前が無視されるという仕掛けである。 + PNG ファイルとして読むときは PNG フッタ以降は無視され、PHP スクリプトとして読むときは PHP タグ以前が無視されるという仕掛けである。

        - strings コマンドを使うと、隠されたデータを簡単に閲覧できる。 + strings コマンドを使うと、隠されたデータを簡単に閲覧できる。

        IHDR
        @@ -271,24 +271,24 @@ $h = $b[24]+2;
         // (以下略)

        - IHDRIEND が PNG 画像の一部で、<?php からが実際のプログラムになっている。 もちろんこれを PHP プログラムとして動かすと、PHP タグより前にある PNG 画像としてのデータはそのまま標準出力へと出力されてしまう。 それを防ぐため、QR コードを読み込んだときの実行方法 + IHDRIEND が PNG 画像の一部で、<?php からが実際のプログラムになっている。もちろんこれを PHP プログラムとして動かすと、PHP タグより前にある PNG 画像としてのデータはそのまま標準出力へと出力されてしまう。それを防ぐため、QR コードを読み込んだときの実行方法

        Guess password. $ echo "password" | php Q1.png >/dev/null

        - には標準出力を捨てるよう >/dev/null と指定されている。 + には標準出力を捨てるよう >/dev/null と指定されている。

        - なお、このように PNG 画像などに本来のデータとは異なる別のデータを隠すことを「ステガノグラフィ」(Wikipedia「ステガノグラフィー」) と呼ぶ。 + なお、このように PNG 画像などに本来のデータとは異なる別のデータを隠すことを「ステガノグラフィ」(Wikipedia「ステガノグラフィー」) と呼ぶ。

        実行される PHP プログラム

        - 画像の正体がわかったところで、画像に隠されていた PHP プログラムについて見ていこう。 先ほどは一部しか記載しなかったので、全体を載せる。 なお、ある程度ゴルフしながら書いたので、空白こそ残しているものの可読性は非常に低いことと思う。 + 画像の正体がわかったところで、画像に隠されていた PHP プログラムについて見ていこう。先ほどは一部しか記載しなかったので、全体を載せる。なお、ある程度ゴルフしながら書いたので、空白こそ残しているものの可読性は非常に低いことと思う。

        <?php
        @@ -394,7 +394,7 @@ $h = $b[24]+2;
         fwrite(STDERR, str_replace('403 Forbidden', '401 Unauthorized', $o));

        - これは一体なんなのか。ずばり、難解プログラミング言語の一つ Piet のインタプリタである。 Piet はピエト・モンドリアン (『赤・青・黄のコンポジション』などで知られる抽象画家) の作品にインスピレーションを受けて作られた、画像をソースコードとするプログラミング言語である。 インタプリタは画像の各ピクセルの上を進みながら、色等に応じて特定の処理をおこなっていく。 ここでは詳しい言語仕様については解説しないので、気になる方は Wikipedia の記事「Piet」 などを参照してほしい。 + これは一体なんなのか。ずばり、難解プログラミング言語の一つ Piet のインタプリタである。Piet はピエト・モンドリアン (『赤・青・黄のコンポジション』などで知られる抽象画家) の作品にインスピレーションを受けて作られた、画像をソースコードとするプログラミング言語である。インタプリタは画像の各ピクセルの上を進みながら、色等に応じて特定の処理をおこなっていく。ここでは詳しい言語仕様については解説しないので、気になる方は Wikipedia の記事「Piet」 などを参照してほしい。

        @@ -404,18 +404,18 @@ $h = $b[24]+2;

        $b = unpack('C*', file_get_contents(__FILE__));

        - で __FILE__ つまりこの画像ファイルを読み込んでいる。 先ほど Piet は画像をソースコードにしていると説明した。 そう、今回の問題の画像ファイル Q1.png は、PHP 製 Piet インタプリタであると同時に、Piet のソースコード画像でもあるのだ。 QR コード中央のカラフルな部分が Piet の命令になっている。 + で __FILE__ つまりこの画像ファイルを読み込んでいる。先ほど Piet は画像をソースコードにしていると説明した。そう、今回の問題の画像ファイル Q1.png は、PHP 製 Piet インタプリタであると同時に、Piet のソースコード画像でもあるのだ。QR コード中央のカラフルな部分が Piet の命令になっている。

        Piet のソースコード

        - さて、Piet でどのようなコードが書かれて (いや、描かれて) いるのかを解説したいところだが、今の私にはできそうにない。 というのも、すでに述べたように Piet は「難解プログラミング言語」である。 およそ人が描いたり読んだりするようには作られていない。性質としては、パズルに近い代物である。 + さて、Piet でどのようなコードが書かれて (いや、描かれて) いるのかを解説したいところだが、今の私にはできそうにない。というのも、すでに述べたように Piet は「難解プログラミング言語」である。およそ人が描いたり読んだりするようには作られていない。性質としては、パズルに近い代物である。

        - というわけで、ここではあらましを説明するだけでご容赦いただきたい。 それぞれの部分はおおよそ次のようなことをやっている (再検証・再読解はしていないので大嘘かもしれない)。 + というわけで、ここではあらましを説明するだけでご容赦いただきたい。それぞれの部分はおおよそ次のようなことをやっている (再検証・再読解はしていないので大嘘かもしれない)。

          @@ -457,7 +457,7 @@ $h = $b[24]+2;

        - ところで、先ほど掲載した Piet のインタプリタのソースコード末尾には次のような箇所がある。 + ところで、先ほど掲載した Piet のインタプリタのソースコード末尾には次のような箇所がある。

        // The original Piet image is wrong: it outputs 403 error for invalid passwords.
        @@ -467,26 +467,26 @@ $h = $b[24]+2;
         fwrite(STDERR, str_replace('403 Forbidden', '401 Unauthorized', $o));

        - コメントにも書かれているが、この Piet のソースコード画像には誤りがあった。 本来 HTTP のステータスコードを真似るのなら、認証の失敗には 401 を返さなければならない。 しかし、Piet のソースは 403 を返すように書いてしまっていた。 そのことに私が気付いたのは PHPerKaigi 2023 が開催されるひと月前で、その時点で私はこの Piet のソースコードを (ちょうどこの記事でそうなっているのと同じように) 読解できなくなっていた。 さらに悪いことに、正しいメッセージ「401 Unauthorized」は元の「403 Forbidden」よりも3文字長い。 3文字出力が長くなるということは、それだけ Piet で塗るべきピクセルが増えることを意味する。 もはや3文字追加で出力するだけの余白はこの画像に残されていなかった (と思う。腕ききの Piet プログラマならできるかもしれないので挑戦してみてほしい)。 + コメントにも書かれているが、この Piet のソースコード画像には誤りがあった。本来 HTTP のステータスコードを真似るのなら、認証の失敗には 401 を返さなければならない。しかし、Piet のソースは 403 を返すように書いてしまっていた。そのことに私が気付いたのは PHPerKaigi 2023 が開催されるひと月前で、その時点で私はこの Piet のソースコードを (ちょうどこの記事でそうなっているのと同じように) 読解できなくなっていた。さらに悪いことに、正しいメッセージ「401 Unauthorized」は元の「403 Forbidden」よりも3文字長い。3文字出力が長くなるということは、それだけ Piet で塗るべきピクセルが増えることを意味する。もはや3文字追加で出力するだけの余白はこの画像に残されていなかった (と思う。腕ききの Piet プログラマならできるかもしれないので挑戦してみてほしい)。

        - これを解決するために私が選んだのは、インタプリタを改造し、本来のメッセージとは異なるメッセージを無理やり出力させて帳尻を合わせることだった。 そういうわけでこの Piet インタプリタは完全な Piet インタプリタではなく、「403 Forbidden」というテキストを絶対に出力できない。 + これを解決するために私が選んだのは、インタプリタを改造し、本来のメッセージとは異なるメッセージを無理やり出力させて帳尻を合わせることだった。そういうわけでこの Piet インタプリタは完全な Piet インタプリタではなく、「403 Forbidden」というテキストを絶対に出力できない。

        その他小ネタ

        - ここまでで問題の核心部分は説明し終えたので、ここからは残った小ネタを紹介しておく。 + ここまでで問題の核心部分は説明し終えたので、ここからは残った小ネタを紹介しておく。

        - この問題のタイトル『An Art of Computer Programming』は、ドナルド・クヌースの『The Art of Computer Programming』をパロディしたものである。 + この問題のタイトル『An Art of Computer Programming』は、ドナルド・クヌースの『The Art of Computer Programming』をパロディしたものである。

        - この問題で得られるトークン「#ModernPHPisStaticallyTypedLanguage」は特に元ネタがあるわけではない。当然のような顔で嘘を主張したかったのでこうなった。 + この問題で得られるトークン「#ModernPHPisStaticallyTypedLanguage」は特に元ネタがあるわけではない。当然のような顔で嘘を主張したかったのでこうなった。

        @@ -494,7 +494,7 @@ $h = $b[24]+2;

        おわりに

        - この問題の自己評価はこちら。 問題の出題順はおおよそ作成した順になっているのだが、そのせいで難易度高めの問題が1問目に配置されてしまった。 これは反省点の一つである。 + この問題の自己評価はこちら。問題の出題順はおおよそ作成した順になっているのだが、そのせいで難易度高めの問題が1問目に配置されてしまった。これは反省点の一つである。

          diff --git a/vhosts/blog/public/posts/2025-01-26/yaml-breaking-changes-between-v1-1-and-v1-2/index.html b/vhosts/blog/public/posts/2025-01-26/yaml-breaking-changes-between-v1-1-and-v1-2/index.html index d2dfaeae..a8f72a21 100644 --- a/vhosts/blog/public/posts/2025-01-26/yaml-breaking-changes-between-v1-1-and-v1-2/index.html +++ b/vhosts/blog/public/posts/2025-01-26/yaml-breaking-changes-between-v1-1-and-v1-2/index.html @@ -66,14 +66,14 @@ NOTE
          - この記事は、2021-06-30 にデジタルサーカス株式会社 の社内 Qiita Team に公開された記事をベースに、加筆修正して一般公開したものです。 + この記事は、2021-06-30 にデジタルサーカス株式会社 の社内 Qiita Team に公開された記事をベースに、加筆修正して一般公開したものです。

          はじめに

          - データ記述言語の一つ YAML には 1.0、1.1、1.2 のバージョンがある。 これらのうち、1.1 と 1.2 の間には無視できない非互換の変更が多く、1.2 に対応していないライブラリもある (Ruby 同梱の yaml など)。 この記事では、YAML 1.1 と YAML 1.2 の主な破壊的変更を紹介する (影響範囲が広いものを抜粋しており、すべての非互換を網羅してはいない)。 + データ記述言語の一つ YAML には 1.0、1.1、1.2 のバージョンがある。これらのうち、1.1 と 1.2 の間には無視できない非互換の変更が多く、1.2 に対応していないライブラリもある (Ruby 同梱の yaml など)。この記事では、YAML 1.1 と YAML 1.2 の主な破壊的変更を紹介する (影響範囲が広いものを抜粋しており、すべての非互換を網羅してはいない)。

          @@ -86,21 +86,21 @@

          Boolean としてパースされるトークンが true / false とその亜種のみに

          - この変更の影響が最も大きいと思われる。 YAML 1.1 では、boolean 値のリテラルとして truefalse のほか yesnoynonoff、それらの大文字バージョンなどが認められていた。 YAML 1.2 では、truefalse、それらの大文字バージョン (TrueTRUEFalseFALSE) のみが boolean としてパースされるようになった。 + この変更の影響が最も大きいと思われる。YAML 1.1 では、boolean 値のリテラルとして truefalse のほか yesnoynonoff、それらの大文字バージョンなどが認められていた。YAML 1.2 では、truefalse、それらの大文字バージョン (TrueTRUEFalseFALSE) のみが boolean としてパースされるようになった。

          八進数リテラルには 0o が必須に

          - C 言語などでは、0 から始まる数字の列を八進数としてパースする。 YAML 1.1 もこれに準じていたが、1.2 からは 0o のプレフィクスが必須となった ("o" は "octal" の "o")。 プログラミング言語では、Python や Haskell、Swift、Rust などがこの記法を採用している。 + C 言語などでは、0 から始まる数字の列を八進数としてパースする。YAML 1.1 もこれに準じていたが、1.2 からは 0o のプレフィクスが必須となった ("o" は "octal" の "o")。プログラミング言語では、Python や Haskell、Swift、Rust などがこの記法を採用している。

          << によるマージが不可能に

          - YAML 1.1 では、<< という文字列をキーに指定することで、マップをマージすることができた。 + YAML 1.1 では、<< という文字列をキーに指定することで、マップをマージすることができた。

          x: &base
          @@ -113,14 +113,14 @@
           # => { "y": { "a": 123, "b": 456 } }

          - 1.2 からはこれができなくなる。 + 1.2 からはこれができなくなる。

          数字を _ で区切るのが禁止に

          - 12345671_234_567 と書けなくなった。 + 12345671_234_567 と書けなくなった。

          @@ -128,7 +128,7 @@

          おわりに

          - 全体的に、There's more than one way to do it. から There should be one - and preferably only one - obvious way to do it. へ移行しているように思われる。 データ記述言語としては望ましい方向性ではないかと感じる。 + 全体的に、There's more than one way to do it. から There should be one - and preferably only one - obvious way to do it. へ移行しているように思われる。データ記述言語としては望ましい方向性ではないかと感じる。

          diff --git a/vhosts/blog/public/posts/2025-02-24/phpcon-nagoya-2025-report/index.html b/vhosts/blog/public/posts/2025-02-24/phpcon-nagoya-2025-report/index.html index c4cc74c7..e929808e 100644 --- a/vhosts/blog/public/posts/2025-02-24/phpcon-nagoya-2025-report/index.html +++ b/vhosts/blog/public/posts/2025-02-24/phpcon-nagoya-2025-report/index.html @@ -67,14 +67,14 @@

          はじめに

          - 2025-02-22 に開催されたPHP カンファレンス名古屋に参加した。 + 2025-02-22 に開催されたPHP カンファレンス名古屋に参加した。

          セッション感想

          - 特に印象に残ったセッションを二つピックアップした (タイトルと発表者名は fortee のプロポーザルページによる)。 + 特に印象に残ったセッションを二つピックアップした (タイトルと発表者名は fortee のプロポーザルページによる)。

            @@ -101,22 +101,22 @@

            登壇したセッション

            - 「PHP 処理系の garbage collection を理解する 〜メモリはいつ解放されるのか〜」というタイトルで登壇もおこなった。タイトルどおり、PHP の garbage collection (GC) について扱った発表である。 + 「PHP 処理系の garbage collection を理解する 〜メモリはいつ解放されるのか〜」というタイトルで登壇もおこなった。タイトルどおり、PHP の garbage collection (GC) について扱った発表である。

            - 技術的な内容としてはPHP のマニュアルの GC に関する記述を出ていないものの、PHP 処理系の内部的な用語を使わないようにしたり、本質的でない処理を省いたりして、理解のための前提条件を減らせたのではないかと思う。 + 技術的な内容としてはPHP のマニュアルの GC に関する記述を出ていないものの、PHP 処理系の内部的な用語を使わないようにしたり、本質的でない処理を省いたりして、理解のための前提条件を減らせたのではないかと思う。

            - ところで今回スライドのフォントサイズを大きくするために各スライドの見出し部分を消してみたのだが、結局ほとんどのスライドで見出しらしき文言が必要になったので、あまり効果はなかったかもしれない。 + ところで今回スライドのフォントサイズを大きくするために各スライドの見出し部分を消してみたのだが、結局ほとんどのスライドで見出しらしき文言が必要になったので、あまり効果はなかったかもしれない。

            おわりに

            - 今回もカンファレンスくらいでしか聴けないようなセッションがいくつも聴けてよかった。 また、ちょうど連休だったのもあり名古屋も楽しむことができた。 運営のみなさま、お疲れさまでした&ありがとうございました。 次は PHPerKaigi 2025 で会いましょう。 + 今回もカンファレンスくらいでしか聴けないようなセッションがいくつも聴けてよかった。また、ちょうど連休だったのもあり名古屋も楽しむことができた。運営のみなさま、お疲れさまでした&ありがとうございました。次は PHPerKaigi 2025 で会いましょう。

            -- cgit v1.2.3-70-g09d2