summaryrefslogtreecommitdiffhomepage
path: root/vhosts/blog/public/posts
diff options
context:
space:
mode:
Diffstat (limited to 'vhosts/blog/public/posts')
-rw-r--r--vhosts/blog/public/posts/2021-03-05/my-first-post/index.html63
-rw-r--r--vhosts/blog/public/posts/2021-03-30/phperkaigi-2021/index.html1031
-rw-r--r--vhosts/blog/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html200
-rw-r--r--vhosts/blog/public/posts/2021-10-02/python-unbound-local-error/index.html130
-rw-r--r--vhosts/blog/public/posts/2021-10-02/ruby-detect-running-implementation/index.html217
-rw-r--r--vhosts/blog/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html290
-rw-r--r--vhosts/blog/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html258
-rw-r--r--vhosts/blog/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html224
-rw-r--r--vhosts/blog/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html253
-rw-r--r--vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html605
-rw-r--r--vhosts/blog/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html166
-rw-r--r--vhosts/blog/public/posts/2022-05-01/phperkaigi-2022/index.html268
-rw-r--r--vhosts/blog/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html192
-rw-r--r--vhosts/blog/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html116
-rw-r--r--vhosts/blog/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html739
-rw-r--r--vhosts/blog/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html212
-rw-r--r--vhosts/blog/public/posts/2022-10-28/setup-server-for-this-site/index.html316
-rw-r--r--vhosts/blog/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html225
-rw-r--r--vhosts/blog/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html410
-rw-r--r--vhosts/blog/public/posts/2023-03-10/rewrite-this-blog-generator/index.html166
-rw-r--r--vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html745
-rw-r--r--vhosts/blog/public/posts/2023-04-04/phperkaigi-2023-report/index.html307
-rw-r--r--vhosts/blog/public/posts/2023-06-25/phpconfuk-2023-report/index.html161
-rw-r--r--vhosts/blog/public/posts/index.html389
24 files changed, 7683 insertions, 0 deletions
diff --git a/vhosts/blog/public/posts/2021-03-05/my-first-post/index.html b/vhosts/blog/public/posts/2021-03-05/my-first-post/index.html
new file mode 100644
index 00000000..d0e38c41
--- /dev/null
+++ b/vhosts/blog/public/posts/2021-03-05/my-first-post/index.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="これはテスト投稿です。これはテスト投稿です。これはテスト投稿です。">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>My First Post | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">My First Post</h1>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2021-03-05">2021-03-05</time>: 公開
+ </li>
+ </ol>
+ </section>
+ <section id="section--test">
+ <h2><a href="#section--test">Test</a></h2>
+ <p>
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..dbdd4de1
--- /dev/null
+++ b/vhosts/blog/public/posts/2021-03-30/phperkaigi-2021/index.html
@@ -0,0 +1,1031 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。">
+ <meta name="keywords" content="カンファレンス,PHP,PHPerKaigi">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHPerKaigi 2021 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHPerKaigi 2021</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/conference/">カンファレンス</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/phperkaigi/">PHPerKaigi</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2021-03-30">2021-03-30</time>: 公開
+ </li>
+ </ol>
+ </section>
+ <section id="section--report">
+ <h2><a href="#section--report">PHPerKaigi 2021 参加レポ</a></h2>
+ <p>
+ 2021-03-26 から 2021-03-28 にかけて開催された、 <a href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</a> に一般参加者として参加した。 弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> (今年1月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。
+ </p>
+
+ <p>
+ このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。
+ </p>
+
+ <p>
+ 発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。
+ </p>
+
+ <section id="section--report-legend">
+ <h3><a href="#section--report-legend">凡例</a></h3>
+ <blockquote>
+ <p>
+ 発表・スライドのメモ (引用ではない)
+ </p>
+ </blockquote>
+
+ <p>
+ 感想など
+ </p>
+ </section>
+
+ <section id="section--report--day-0">
+ <h3><a href="#section--report--day-0">Day 0 前夜祭 (2021/03/27)</a></h3>
+ <section id="section--report--day-0--1730-a">
+ <h4><a href="#section--report--day-0--1730-a">17:30 [A]</a></h4>
+ <p>
+ PHP で AWS Lambda
+ </p>
+
+ <blockquote>
+ <p>
+ Rails のプロジェクトを PHPer のメンバのみでメンテ →他のメンバもわかる PHP にリプレースを検討
+ </p>
+
+ <ul>
+ <li>
+ サーバレス
+ </li>
+
+ <li>
+ サーバ・インフラの管理が不要
+ </li>
+
+ <li>
+ アプリケーションコードの知識だけで保守可能
+ </li>
+ </ul>
+
+ <p>
+ ゼロベースで作れる案件が (Railsの件とは別に) あるため、そちらで試験的に導入?
+ </p>
+
+ <p>
+ AWSの学習 AWS のドキュメント DevelopersIO
+ </p>
+
+ <p>
+ AWS Lambda のカスタムランタイムで PHP を動かす
+ </p>
+
+ <p>
+ サーバのセットアップや維持管理を気にしなくて良い サーバーレスで PHP を動かすツールがすでにある サーバーレス構築はすんなり
+ </p>
+
+ <p>
+ 今は Laravel がルーティングしている Laravel Livewire を Lambda に載せられないか? デプロイ方法は? バッチ処理は? (Lambda は 15分の制限)
+ </p>
+
+ <p>
+ Lambda でコンテナイメージがサポートされるように
+ </p>
+
+ <p>
+ 抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる
+ </p>
+ </blockquote>
+
+ <p>
+ AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。
+ </p>
+
+ <p>
+ PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。
+ </p>
+
+ <p>
+ 勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。
+ </p>
+ </section>
+
+ <section id="section--report--day-0--1810-a">
+ <h4><a href="#section--report--day-0--1810-a">18:10 [A]</a></h4>
+ <p>
+ 大規模サイトの SEO
+ </p>
+
+ <blockquote>
+ <p>
+ 大規模サイト (100万ページ以上) Google の基準
+ </p>
+
+ <p>
+ クロールバジェットを意識したSEO
+ </p>
+
+ <p>
+ 大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト (10,000以上) でコンテンツが目まぐるしく変更される これを満たさないなら、クロールバジェットを考えなくてもいい
+ </p>
+
+ <p>
+ サーチコンソール 「カバレッジ」の「除外」 多すぎるのは問題→クロールバジェットを浪費している
+ </p>
+
+ <ul>
+ <li>
+ クエリの順番を決める
+ </li>
+
+ <li>
+ 空の値のルールを決めておく
+ </li>
+
+ <li>
+ リダイレクトすればインデックスはうまくいく
+ </li>
+
+ <li>
+ リンクが存在する限りクロールはされる
+ </li>
+ </ul>
+
+ <p>
+ リニューアル前のURL
+ </p>
+
+ <p>
+ インデックスは移行される リンクのURLが存在する限り、別のURLとしてクロールされる リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い リニューアルで無視されるようになったパラメータも注意
+ </p>
+
+ <p>
+ robotes.txt で拒否しているのにクロールされる 一時的に拒否を外して 404 や 301 を読ませる 内部リンクを確認する JS でのリンクに書き換え
+ </p>
+
+ <p>
+ クエリパラメータからURLのパスに <code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code>
+ </p>
+
+ <p>
+ URL 設計だいじ
+ </p>
+ </blockquote>
+
+ <p>
+ SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。
+ </p>
+ </section>
+
+ <section id="section--report--day-0--1850-a">
+ <h4><a href="#section--report--day-0--1850-a">18:50 [A]</a></h4>
+ <blockquote>
+ <p>
+ 知覚可能 操作可能 理解可能 堅牢 ちゃんとしたHTMLを書く (閉じタグ・入れ子構造など)
+ </p>
+
+ <ul>
+ <li>
+ 標準の HTML を適切に使う
+ </li>
+
+ <li>
+ WAI-ARIA
+ </li>
+
+ <li>
+ キーボードフレンドリー
+ </li>
+
+ <li>
+ マシンフレンドリー
+ </li>
+
+ <li>
+ SEOフレンドリー
+ </li>
+ </ul>
+
+ <p>
+ button タグ →キーボード h1 タグ →スクリーンリーダー・クローラ a タグ
+ </p>
+
+ <p>
+ WAI-ARIA HTML では表現できないセマンティクスを追加する
+ </p>
+
+ <ul>
+ <li>
+ ロール
+ <ul>
+ <li>
+ 何をするのか?
+ </li>
+
+ <li>
+ ユーザーアクションによって変化しない
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ プロパティ
+ <ul>
+ <li>
+ 関連づけられたデータ
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ ステート
+ <ul>
+ <li>
+ 現在の状態
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>
+ まずは標準の HTML 要素で解決する 何でもかんでも WAI-ARIA を使えばいいというものではない
+ </p>
+
+ <p>
+ マウスホバーでツールチップが出てくるが、キーボード操作では出てこない
+ </p>
+
+ <p>
+ VoiceOver
+ </p>
+
+ <p>
+ 全ての属性を使う必要はない あくまでアクセシビリティを上げるための方法の一つにすぎない
+ </p>
+ </blockquote>
+
+ <p>
+ つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。
+ </p>
+ </section>
+
+ <section id="section--report--day-0--1930-a">
+ <h4><a href="#section--report--day-0--1930-a">19:30 [A]</a></h4>
+ <p>
+ PHP で FUSE
+ </p>
+
+ <p>
+ 個人的に楽しみだった発表。
+ </p>
+
+ <blockquote>
+ <p>
+ VFS (virtual filesystem) vs 具体的なファイルシステム
+ </p>
+
+ <p>
+ 最適な実装方法は状況により異なる
+ </p>
+
+ <p>
+ アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS
+ </p>
+
+ <p>
+ カーネルのプログラムを作るのは難しい * 権限がデカすぎる * システム全体がクラッシュ * セキュリティリスク * 開発サイクルを回しづらい * ネイティブコードにコンパイルされる言語である必要がある
+ </p>
+
+ <p>
+ Filesystem in USEr space (FUSE)
+ </p>
+
+ <ul>
+ <li>
+ 特定の C の関数を呼ぶことで filesystem が作れる
+ </li>
+
+ <li>
+ FFI を持つ言語なら FUSE が使える
+ </li>
+ </ul>
+
+ <p>
+ SSHFS / s3fs / Docker Desktop
+ </p>
+
+ <p>
+ Linux 以外でも使える
+ </p>
+
+ <ul>
+ <li>
+ dokany (on Windows)
+ </li>
+
+ <li>
+ osxfuse
+ </li>
+ </ul>
+
+ <p>
+ VFS: システムコールが呼ばれると、ファイルシステムによってコール FUSE: カーネル空間からユーザ空間へ通信
+ </p>
+
+ <p>
+ 高レベルなラッパで型をつける
+ </p>
+
+ <p>
+ PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)
+ </p>
+
+ <ul>
+ <li>
+ grep できる
+ </li>
+
+ <li>
+ sed できる
+ </li>
+
+ <li>
+ 編集できる
+ </li>
+ </ul>
+ </blockquote>
+
+ <p>
+ 期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。 この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。
+ </p>
+ </section>
+ </section>
+
+ <section id="section--report--day-1">
+ <h3><a href="#section--report--day-1">Day 1 (2021/03/27)</a></h3>
+ <section id="section--report--day-1--1050-a">
+ <h4><a href="#section--report--day-1--1050-a">10:50 [A]</a></h4>
+ <p>
+ ATDD
+ </p>
+
+ <blockquote>
+ <ul>
+ <li>
+ ユーザーストーリー
+ </li>
+
+ <li>
+ ユニットテスト
+ </li>
+
+ <li>
+ CI/CD
+ </li>
+ </ul>
+
+ <p>
+ ユーザストーリーの受け入れ条件が曖昧になりがち デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている
+ </p>
+
+ <p>
+ Q2の強化 アジャイルテストの4象限
+ </p>
+
+ <p>
+ 技術面/ビジネス面 開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)
+ </p>
+
+ <ul>
+ <li>
+ Q1: 技術面 &amp; チーム支援
+ <ul>
+ <li>
+ TDD
+ </li>
+
+ <li>
+ ユニットテストなど
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ Q2: ビジネス面 &amp; チーム支援
+ <ul>
+ <li>
+ ATDD
+ </li>
+
+ <li>
+ ビジネス面の受け入れテストで駆動する
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>
+ Agile Alliance ユーザストーリーのスキルレベルを高める
+ </p>
+
+ <p>
+ テストピラミッド
+ </p>
+
+ <ul>
+ <li>
+ UI Tests
+ </li>
+
+ <li>
+ Service Tests
+ </li>
+
+ <li>
+ Unit Tests
+ </li>
+
+ <li>
+ 異なる粒度のテストを書く
+ </li>
+
+ <li>
+ 高レベルになるほど、持つべきテストは少なくなる
+ <ul>
+ <li>
+ ピラミッド型になる
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>
+ 高レベルテストが多すぎる→アイスクリームコーン アンチパターン
+ </p>
+
+ <p>
+ ATDD (Acceptance TDD) API経由・UI経由での高レベルテスト E2E test
+ </p>
+
+ <p>
+ ストーリ受け入れテスト
+ </p>
+
+ <p>
+ 入れ子のフィードバックループ ATDD(外側) と TDD(内側)
+ </p>
+
+ <p>
+ 外部品質・内部品質
+ </p>
+
+ <p>
+ バーティカルスライスのデリバリー
+ </p>
+
+ <ul>
+ <li>
+ cucumber
+ </li>
+
+ <li>
+ gauge
+ </li>
+
+ <li>
+ behat
+ </li>
+ </ul>
+
+ <p>
+ ユビキタス言語 手動テストもspecに書く 自動化は可能だがコスパが悪い 失敗することがわかっているテスト(レッドテスト)はCIから外す 失敗時の原因究明が難しい 饒舌なエラーメッセージ 状況のスナップショット
+ </p>
+
+ <p>
+ Continuous Testing
+ </p>
+ </blockquote>
+
+ <p>
+ User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。 高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。
+ </p>
+ </section>
+
+ <section id="section--report--day-1--1150-a">
+ <h4><a href="#section--report--day-1--1150-a">11:50 [A]</a></h4>
+ <p>
+ 型解析を用いたリファクタリング
+ </p>
+
+ <p>
+ 型のある世界で生きてきた身として大いに楽しみにしていた発表。
+ </p>
+
+ <blockquote>
+ <ul>
+ <li>
+ PHPStan
+ </li>
+
+ <li>
+ Phan
+ </li>
+
+ <li>
+ Psalm
+ </li>
+ </ul>
+
+ <p>
+ autoload も認識できる bootstrapFiles
+ </p>
+
+ <p>
+ 編集箇所と利用箇所を CI でチェック ルールレベルを徐々に引き上げていく 警告が多すぎると見落としてしまう・無視されやすくなる
+ </p>
+
+ <p>
+ 型がついていないことによるエラーが多い
+ </p>
+
+ <p>
+ 型よりも詳細な検査 <code>Util_Assert::min</code>
+ </p>
+
+ <p>
+ SQL を静的解析 placeholder の型付け
+ </p>
+
+ <p>
+ 警告レベルを低いレベルから導入 タイプヒントを積極的に書いていく PHPStan の拡張を追加する
+ </p>
+ </blockquote>
+
+ <p>
+ 昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。 今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。
+ </p>
+ </section>
+
+ <section id="section--report--day-1--1230-a">
+ <h4><a href="#section--report--day-1--1230-a">12:30 [A]</a></h4>
+ <p>
+ 昼食をとっていた。事前に何か食料を買っておくべきだった。
+ </p>
+ </section>
+
+ <section id="section--report--day-1--1310-a">
+ <h4><a href="#section--report--day-1--1310-a">13:10 [A]</a></h4>
+ <p>
+ Documentation as Code
+ </p>
+
+ <p>
+ この発表も以前から非常に楽しみにしていた。
+ </p>
+
+ <blockquote>
+ <p>
+ 開発開始までのオーバーヘッド 新規にチームにジョイン 担当範囲外の機能を理解 オンボーディングのコスト
+ </p>
+
+ <p>
+ PHPerKaigi 2020 で発表あり
+ </p>
+
+ <p>
+ 継続的にシステムの理解を助けるドキュメント
+ </p>
+
+ <p>
+ 継続的ドキュメンテーション システムとドキュメントの乖離
+ </p>
+
+ <p>
+ 書いてあることが間違っている・足りない * 徐々にずれていく * システムの更新タイミングとドキュメントの更新タイミングに差がある
+ </p>
+
+ <p>
+ システムとドキュメントは対応関係がある * 間違ったドキュメント * 存在しないドキュメント
+ </p>
+
+ <p>
+ システムとドキュメントの乖離を定量化する 継続的に システムの更新に近いタイミングで ドキュメントを更新し続ける
+ </p>
+
+ <p>
+ Documentation as Code
+ </p>
+
+ <p>
+ コードと同じツールでドキュメントを書く * issue tracker * vcs * plain text markup * automation
+ </p>
+
+ <p>
+ 開発者 システム ドキュメント 構造化データ ソフトウェア
+ </p>
+
+ <p>
+ システムから構造化データを抽出する PHPDoc OpenAPI
+ </p>
+
+ <p>
+ ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する
+ </p>
+
+ <p>
+ ビューの単位でドキュメントに
+ </p>
+
+ <p>
+ スタックトレースからのドキュメント生成
+ </p>
+ </blockquote>
+
+ <p>
+ ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。
+ </p>
+ </section>
+
+ <section id="section--report--day-1--1410-a">
+ <h4><a href="#section--report--day-1--1410-a">14:10 [A]</a></h4>
+ <p>
+ cookie による session 管理
+ </p>
+
+ <p>
+ 全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。
+ </p>
+ </section>
+
+ <section id="section--report--day-1--1450-a">
+ <h4><a href="#section--report--day-1--1450-a">14:50 [A]</a></h4>
+ <p>
+ PHP のエラーと例外
+ </p>
+
+ <blockquote>
+ <p>
+ エラー PHPエンジンがエラーを通知する 例外 プログラムが投げる
+ </p>
+
+ <p>
+ PHP7-8とエラー
+ </p>
+
+ <p>
+ PHPエンジンのエラーの一部が に変換されるようになった → try-catch で捕捉できる
+ </p>
+
+ <p>
+ は例外とは異なる
+ </p>
+
+ <p>
+ PHP8 でエラーレベルの引き上げ
+ </p>
+
+ <ul>
+ <li>
+ 捕捉すべきもの
+ <ul>
+ <li>
+ recoverable
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ 捕捉すべきでないもの
+ <ul>
+ <li>
+ unrecoverable
+ </li>
+
+ <li>
+ 開発時に対処できるもの
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>
+ 例外 * 捕捉して事後処理 * 捕捉せず(or 捕捉した上で)さらに上に是非を問う
+ </p>
+
+ <p>
+ 開発段階で例外を把握し、ハンドリングを考えておく
+ </p>
+
+ <p>
+ と
+ </p>
+
+ <p>
+ はキャッチすべきでない
+ </p>
+
+ <ul>
+ <li>
+ <p>
+ </p>
+
+ <ul>
+ <li>
+ 本番で起きてはいけない
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ <p>
+ </p>
+
+ <ul>
+ <li>
+ 本番で起きてはいけない →生じないのだから捕捉もしない
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ <p>
+ </p>
+
+ <ul>
+ <li>
+ 起こるかもしれないので本番環境でも考慮する
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>
+ 捕捉して対応するのではなく、未然に防ぐ
+ </p>
+
+ <p>
+ 独自例外を使う を投げてしまうと、 catch ()せざるを得ない →catch 範囲が広すぎる
+ </p>
+
+ <p>
+ SPL の例外を使う
+ </p>
+
+ <p>
+ 例外翻訳 上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する 下位レイヤの知識に依存させない
+ </p>
+
+ <p>
+ @throws 捕捉してほしい例外を書き連ねておく
+ </p>
+
+ <p>
+ 呼び出しもとに負わせたい責任
+ </p>
+ </blockquote>
+
+ <p>
+ PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。
+ </p>
+
+ <p>
+ 個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。
+ </p>
+
+ <p>
+ PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。
+ </p>
+ </section>
+
+ <section id="section--report--day-1--1530-a">
+ <h4><a href="#section--report--day-1--1530-a">15:30 [A]</a></h4>
+ <p>
+ Laravel のメール認証
+ </p>
+
+ <p>
+ Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。
+ </p>
+ </section>
+
+ <section id="section--report--day-1--1610-a">
+ <h4><a href="#section--report--day-1--1610-a">16:10 [A]</a></h4>
+ <p>
+ gRPC
+ </p>
+
+ <blockquote>
+ <p>
+ Unary RPCs Server streaming RPCs Client streaming RPCs Bidirectional streaming RPCs
+ </p>
+
+ <p>
+ Protobuf
+ </p>
+
+ <p>
+ 実装とAPIが乖離しにくい 自動生成 複数言語でも相互に使える
+ </p>
+
+ <p>
+ マイクロサービスのサービス通信 スマホアプリ ゲームサーバ
+ </p>
+
+ <p>
+ PHP では?
+ </p>
+
+ <p>
+ PHP ではストリーミングが難しい リクエストごとにプロセスが使い捨て
+ </p>
+
+ <p>
+ PHP ではgRPCのクライアントしか対応していない
+ </p>
+
+ <p>
+ gRPC-Web ブラウザで扱うためのJSライブラリ+プロトコル
+ </p>
+
+ <p>
+ HTTP/1.1 でも使える Unary RPC と Server streaming RPC のみ
+ </p>
+
+ <p>
+ Envoy Nginx などで相互に gRPC と gRPC-Web で変換
+ </p>
+
+ <p>
+ Amp イベント駆動な並行処理のフレームワーク
+ </p>
+
+ <p>
+ HTTP/2 対応
+ </p>
+
+ <p>
+ C#のgRPC-Webが楽
+ </p>
+ </blockquote>
+
+ <p>
+ (発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。
+ </p>
+ </section>
+
+ <section id="section--report--day-1--1650-a">
+ <h4><a href="#section--report--day-1--1650-a">16:50 [A]</a></h4>
+ <p>
+ アーキテクチャテスト
+ </p>
+
+ <blockquote>
+ <p>
+ Independent Core Layer Pattern
+ </p>
+
+ <p>
+ 開発初期のアーキテクチャが崩れる アーキテクチャ観点のコードレビューができない
+ </p>
+
+ <p>
+ どこにクラスを置けばよいか? ドキュメントがない
+ </p>
+
+ <p>
+ アーキテクチャ設計に関する知識が属人化・暗黙知化
+ </p>
+
+ <p>
+ ガイドライン * 最初にルールを決めるのは簡単 * ルール通り作り始めるのも簡単 * →維持するのが難しい、人が決めたものゆえ壊れやすい
+ </p>
+
+ <p>
+ PHP の特性 * クラスは public * 可視性の制御が public / protected / private のみ * 依存関係の制御が困難
+ </p>
+
+ <p>
+ アーキテクチャテスト クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する
+ </p>
+
+ <ul>
+ <li>
+ deptrac
+ </li>
+
+ <li>
+ phpat
+ </li>
+ </ul>
+
+ <p>
+ Independent Core Layer Pattern
+ </p>
+
+ <p>
+ アーキテクチャテストの失敗 * 実装誤り * or アーキテクチャが適切でない * 開発の過程でフィードバックしていく
+ </p>
+
+ <p>
+ モジュラーモノリス→マイクロサービスへ
+ </p>
+ </blockquote>
+ </section>
+ </section>
+
+ <section id="section--report--day-2">
+ <h3><a href="#section--report--day-2">Day 2 (2021/03/28)</a></h3>
+ <p>
+ 冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。
+ </p>
+
+ <p>
+ 残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。
+ </p>
+ </section>
+
+ <section id="section--report--comments">
+ <h3><a href="#section--report--comments">全体の感想</a></h3>
+ <p>
+ Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。
+ </p>
+
+ <p>
+ 今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。
+ </p>
+
+ <p>
+ 1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 まあ初カンファレンスだし、とお茶を濁しておこう。
+ </p>
+
+ <p>
+ さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。
+ </p>
+
+ <p>
+ <hr>
+ </hr>
+ </p>
+
+ <p>
+ 最後になりましたが、毎年の PHPerKaigi 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました! (ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)
+ </p>
+
+ <p>
+ ではまた来年。
+ </p>
+ </section>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..75ba6ea9
--- /dev/null
+++ b/vhosts/blog/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html
@@ -0,0 +1,200 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="C++ の属性構文の属性名には、キーワードが使える。ネタ記事。">
+ <meta name="keywords" content="C++,C++ 17">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【C++】 属性構文の属性名にはキーワードが使える | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【C++】 属性構文の属性名にはキーワードが使える</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/cpp/">C++</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/cpp17/">C++ 17</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+ </ol>
+ </section>
+ <div class="admonition">
+ <div class="admonition-label">
+ NOTE
+ </div>
+ <div class="admonition-content">
+ この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</a>
+ </div>
+ </div>
+
+ <p>
+ タイトル落ち。まずはこのコードを見て欲しい。
+ </p>
+
+ <pre class="highlight" language="cpp" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span>
+
+[[<span class="hljs-keyword">alignas</span>]] [[<span class="hljs-keyword">alignof</span>]] [[<span class="hljs-keyword">and</span>]] [[<span class="hljs-keyword">and_eq</span>]] [[<span class="hljs-keyword">asm</span>]] [[<span class="hljs-keyword">auto</span>]] [[<span class="hljs-keyword">bitand</span>]]
+[[<span class="hljs-keyword">bitor</span>]] [[<span class="hljs-type">bool</span>]] [[<span class="hljs-keyword">break</span>]] [[<span class="hljs-keyword">case</span>]] [[<span class="hljs-keyword">catch</span>]] [[<span class="hljs-type">char</span>]] [[<span class="hljs-type">char16_t</span>]]
+[[<span class="hljs-type">char32_t</span>]] [[<span class="hljs-keyword">class</span>]] [[<span class="hljs-keyword">compl</span>]] [[<span class="hljs-type">const</span>]] [[<span class="hljs-keyword">const_cast</span>]] [[<span class="hljs-keyword">constexpr</span>]]
+[[<span class="hljs-keyword">continue</span>]] [[<span class="hljs-keyword">decltype</span>]] [[<span class="hljs-keyword">default</span>]] [[<span class="hljs-keyword">delete</span>]] [[<span class="hljs-keyword">do</span>]] [[<span class="hljs-type">double</span>]]
+[[<span class="hljs-keyword">dynamic_cast</span>]] [[<span class="hljs-keyword">else</span>]] [[<span class="hljs-keyword">enum</span>]] [[<span class="hljs-keyword">explicit</span>]] [[<span class="hljs-keyword">export</span>]] [[<span class="hljs-keyword">extern</span>]] [[<span class="hljs-literal">false</span>]]
+[[<span class="hljs-keyword">final</span>]] [[<span class="hljs-type">float</span>]] [[<span class="hljs-keyword">for</span>]] [[<span class="hljs-keyword">friend</span>]] [[<span class="hljs-keyword">goto</span>]] [[<span class="hljs-keyword">if</span>]] [[<span class="hljs-keyword">inline</span>]] [[<span class="hljs-type">int</span>]]
+[[<span class="hljs-type">long</span>]] [[<span class="hljs-keyword">mutable</span>]] [[<span class="hljs-keyword">namespace</span>]] [[<span class="hljs-keyword">new</span>]] [[<span class="hljs-keyword">noexcept</span>]] [[<span class="hljs-keyword">not</span>]] [[<span class="hljs-keyword">not_eq</span>]]
+[[<span class="hljs-literal">nullptr</span>]] [[<span class="hljs-keyword">operator</span>]] [[<span class="hljs-keyword">or</span>]] [[<span class="hljs-keyword">or_eq</span>]] [[<span class="hljs-keyword">override</span>]] [[<span class="hljs-keyword">private</span>]]
+[[<span class="hljs-keyword">protected</span>]] [[<span class="hljs-keyword">public</span>]] [[<span class="hljs-keyword">register</span>]] [[<span class="hljs-keyword">reinterpret_cast</span>]] [[<span class="hljs-keyword">return</span>]] [[<span class="hljs-type">short</span>]]
+[[<span class="hljs-type">signed</span>]] [[<span class="hljs-keyword">sizeof</span>]] [[<span class="hljs-type">static</span>]] [[<span class="hljs-keyword">static_assert</span>]] [[<span class="hljs-keyword">static_cast</span>]] [[<span class="hljs-keyword">struct</span>]]
+[[<span class="hljs-keyword">switch</span>]] [[<span class="hljs-keyword">template</span>]] [[<span class="hljs-keyword">this</span>]] [[<span class="hljs-keyword">thread_local</span>]] [[<span class="hljs-keyword">throw</span>]] [[<span class="hljs-literal">true</span>]] [[<span class="hljs-keyword">try</span>]]
+[[<span class="hljs-keyword">typedef</span>]] [[<span class="hljs-keyword">typeid</span>]] [[<span class="hljs-keyword">typename</span>]] [[<span class="hljs-keyword">union</span>]] [[<span class="hljs-type">unsigned</span>]]
+[[<span class="hljs-keyword">virtual</span>]] [[<span class="hljs-type">void</span>]] [[<span class="hljs-keyword">volatile</span>]] [[<span class="hljs-type">wchar_t</span>]] [[<span class="hljs-keyword">while</span>]] [[<span class="hljs-keyword">xor</span>]] [[<span class="hljs-keyword">xor_eq</span>]]
+<span class="hljs-comment">// [[using]]</span>
+<span class="hljs-type">int</span> <span class="hljs-built_in">main</span>() {
+ std::cout &lt;&lt; <span class="hljs-string">&quot;Hello, World!&quot;</span> &lt;&lt; std::endl;
+}</code></pre>
+
+ <blockquote>
+ <p>
+ コンパイラのバージョン $ clang++ –version Apple clang version 11.0.0 (clang-1100.0.33.8) Target: x86_64-apple-darwin19.6.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
+ </p>
+
+ <p>
+ コンパイルコマンド (C17指定) $ clang –std=c++17 hoge.cpp
+ </p>
+ </blockquote>
+
+ <p>
+ この記事から得られるものはこれ以上ないので以下は蛇足になる。
+ </p>
+
+ <p>
+ 別件で cppreference.com の <a href="https://en.cppreference.com/w/cpp/language/identifiers">identifier のページ</a> を読んでいた時、次の文が目に止まった。
+ </p>
+
+ <blockquote>
+ <ul>
+ <li>
+ the identifiers that are keywords cannot be used for other purposes;
+ <ul>
+ <li>
+ The only place they can be used as non-keywords is in an attribute-token. (e.g. [[private]] is a valid attribute) (since C++11)
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </blockquote>
+
+ <p>
+ キーワードでも属性として指定する場合は非キーワードとして使えるらしい。 実際にやってみる。
+ </p>
+
+ <p>
+ 同サイトの <a href="https://en.cppreference.com/w/cpp/keyword">keywords のページ</a> から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。 大量の警告 (unknown attribute `〇〇&apos; ignored) がコンパイラから出力されるが、コンパイルできる。
+ </p>
+
+ <p>
+ 上のコードでは <code>[[using]]</code> をコメントアウトしているが、これは <code>using</code> キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。
+ </p>
+
+ <pre class="highlight" language="cpp" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment">// using の例</span>
+[[<span class="hljs-keyword">using</span> foo: attr1, attr2]] <span class="hljs-type">int</span> x; <span class="hljs-comment">// [[foo::attr1, foo::attr2]] の糖衣構文</span></code></pre>
+
+ <p>
+ C++17 の仕様も見てみる (正確には標準化前のドラフト)。
+ </p>
+
+ <p>
+ 引用元: <a href="https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4">https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4</a>
+ </p>
+
+ <blockquote>
+ <p>
+ If a keyword or an alternative token that satisfies the syntactic requirements of an identifier is contained in an attribute-token, it is considered an identifier.
+ </p>
+ </blockquote>
+
+ <p>
+ 「<code>identifier</code> の構文上の要件を満たすキーワードまたは代替トークンが <code>attribute-token</code> に含まれている場合、<code>identifier</code> とみなされる」とある。どうやら間違いないようだ。
+ </p>
+
+ <p>
+ ところで、代替トークン (alternative token) とは <code>and</code> (<code>&amp;</code>) や <code>bitor</code> (<code>|</code>) などのことだが、<code>identifier</code> の構文上の要件を満たさないような代替トークンなどあるのか? 疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい (参考: <a href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</a>)
+ </p>
+
+ <ul>
+ <li>
+ <code>&lt;%</code> → <code>{</code>
+ </li>
+
+ <li>
+ <code>%&gt;</code> → <code>}</code>
+ </li>
+
+ <li>
+ <code>&lt;:</code> → <code>[</code>
+ </li>
+
+ <li>
+ <code>:&gt;</code> → <code>]</code>
+ </li>
+
+ <li>
+ <code>%:</code> → <code>#</code>
+ </li>
+
+ <li>
+ <code>%:%:</code> → <code>##</code>
+ </li>
+ </ul>
+
+ <p>
+ 「<code>identifier</code> の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。
+ </p>
+
+ <p>
+ 調べた感想: 字句解析器か構文解析器が辛そう
+ </p>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..105b946b
--- /dev/null
+++ b/vhosts/blog/public/posts/2021-10-02/python-unbound-local-error/index.html
@@ -0,0 +1,130 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="Python における UnboundLocalError の理由と対処法。">
+ <meta name="keywords" content="Python,Python 3">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【Python】 クロージャとUnboundLocalError: local variable &apos;x&apos; referenced before assignment | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【Python】 クロージャとUnboundLocalError: local variable &apos;x&apos; referenced before assignment</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/python/">Python</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/python3/">Python 3</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+ </ol>
+ </section>
+ <div class="admonition">
+ <div class="admonition-label">
+ NOTE
+ </div>
+ <div class="admonition-content">
+ この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</a>
+ </div>
+ </div>
+
+ <p>
+ 本記事は Python 3.7.6 の動作結果を元にして書かれている。
+ </p>
+
+ <p>
+ Python でクロージャを作ろうと、次のようなコードを書いた。
+ </p>
+
+ <pre class="highlight" language="python" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">def</span> <span class="hljs-title function_">f</span>():
+ x = <span class="hljs-number">0</span>
+ <span class="hljs-keyword">def</span> <span class="hljs-title function_">g</span>():
+ x += <span class="hljs-number">1</span>
+ g()
+
+f()</code></pre>
+
+ <p>
+ 関数 <code>g</code> から 関数 <code>f</code> のスコープ内で定義された変数 <code>x</code> を参照し、それに 1 を足そうとしている。 これを実行すると <code>x += 1</code> の箇所でエラーが発生する。
+ </p>
+
+ <blockquote>
+ <p>
+ UnboundLocalError: local variable `x&apos; referenced before assignment
+ </p>
+ </blockquote>
+
+ <p>
+ local変数 <code>x</code> が代入前に参照された、とある。これは、<code>f</code> の <code>x</code> を参照するのではなく、新しく別の変数を <code>g</code> 内に作ってしまっているため。 前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<code>var</code> を変数宣言のための構文として擬似的に利用している。
+ </p>
+
+ <pre class="highlight" language="python" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment"># 注: var は正しい Python の文法ではない。上記参照のこと</span>
+<span class="hljs-keyword">def</span> <span class="hljs-title function_">f</span>():
+ var x <span class="hljs-comment"># f の local変数 &#x27;x&#x27; を宣言</span>
+ x = <span class="hljs-number">0</span> <span class="hljs-comment"># x に 0 を代入</span>
+ <span class="hljs-keyword">def</span> <span class="hljs-title function_">g</span>(): <span class="hljs-comment"># f の内部関数 g を定義</span>
+ var x <span class="hljs-comment"># g の local変数 &#x27;x&#x27; を宣言</span>
+ <span class="hljs-comment"># たまたま f にも同じ名前の変数があるが、それとは別の変数</span>
+ x += <span class="hljs-number">1</span> <span class="hljs-comment"># x に 1 を加算 (x = x + 1 の糖衣構文)</span>
+ <span class="hljs-comment"># 加算する前の値を参照しようとするが、まだ代入されていないためエラー</span>
+ g()</code></pre>
+
+ <p>
+ 当初の意図を表現するには、次のように書けばよい。
+ </p>
+
+ <pre class="highlight" language="python" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">def</span> <span class="hljs-title function_">f</span>():
+ x = <span class="hljs-number">0</span>
+ <span class="hljs-keyword">def</span> <span class="hljs-title function_">g</span>():
+ <span class="hljs-keyword">nonlocal</span> x <span class="hljs-comment">## (*)</span>
+ x += <span class="hljs-number">1</span>
+ g()</code></pre>
+
+ <p>
+ <code>(*)</code> のように、<code>nonlocal</code> を追加する。これにより一つ外側のスコープ (<code>g</code> の一つ外側 = <code>f</code>) で定義されている <code>x</code> を探しに行くようになる。
+ </p>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..d9f9e79f
--- /dev/null
+++ b/vhosts/blog/public/posts/2021-10-02/ruby-detect-running-implementation/index.html
@@ -0,0 +1,217 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="Ruby には複数の実装があるが、自身を実行している処理系の種類をスクリプト上からどのように判定すればよいだろうか。">
+ <meta name="keywords" content="Ruby">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【Ruby】 自身を実行している処理系の種類を判定する | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【Ruby】 自身を実行している処理系の種類を判定する</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/ruby/">Ruby</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+ </ol>
+ </section>
+ <div class="admonition">
+ <div class="admonition-label">
+ NOTE
+ </div>
+ <div class="admonition-content">
+ この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791">https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791</a>
+ </div>
+ </div>
+
+ <p>
+ Ruby という言語には複数の実装があるが、それらをスクリプト上からどのようにして programmatically に見分ければよいだろうか。
+ </p>
+
+ <p>
+ <code>Object</code> クラスに定義されている <code>RUBY_ENGINE</code> という定数がこの用途に使える。
+ </p>
+
+ <p>
+ 参考: <a href="https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_ENGINE.html">Object::RUBY_ENGINE</a>
+ </p>
+
+ <p>
+ 上記ページの例から引用する:
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ ruby-1.9.1 -ve &apos;p RUBY_ENGINE&apos;
+ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux]
+&quot;ruby&quot;
+$ jruby -ve &apos;p RUBY_ENGINE&apos;
+jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
+&quot;jruby&quot;</code></pre>
+
+ <p>
+ それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。
+ </p>
+
+ <p>
+ <a href="https://stackoverflow.com/a/9894232">What values for RUBY_ENGINE correspond to which Ruby implementations?</a> より引用:
+ </p>
+
+ <blockquote>
+ <table>
+ <thead>
+ <tr>
+ <td>
+ RUBY_ENGINE
+ </td>
+
+ <td>
+ Implementation
+ </td>
+ </tr>
+ </thead>
+
+ <tbody>
+ <tr>
+ <td>
+ &lt;undefined&gt;
+ </td>
+
+ <td>
+ MRI &lt; 1.9
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ `ruby&apos;
+ </td>
+
+ <td>
+ MRI &gt;= 1.9 or REE
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ `jruby&apos;
+ </td>
+
+ <td>
+ JRuby
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ `macruby&apos;
+ </td>
+
+ <td>
+ MacRuby
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ `rbx&apos;
+ </td>
+
+ <td>
+ Rubinius
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ `maglev&apos;
+ </td>
+
+ <td>
+ MagLev
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ `ironruby&apos;
+ </td>
+
+ <td>
+ IronRuby
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ `cardinal&apos;
+ </td>
+
+ <td>
+ Cardinal
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </blockquote>
+
+ <p>
+ なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も <code>&apos;ruby&apos;</code> が返ってくることを確認済み。
+ </p>
+
+ <p>
+ この表にない主要な処理系として、https://mruby.org[mruby] は <code>&apos;mruby&apos;</code> を返す。
+ </p>
+
+ <p>
+ <a href="https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35">mruby 該当部分のソース</a> より引用:
+ </p>
+
+ <pre class="highlight" language="c" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment">/*
+* Ruby engine.
+*/</span>
+<span class="hljs-meta">#<span class="hljs-keyword">define</span> MRUBY_RUBY_ENGINE <span class="hljs-string">&quot;mruby&quot;</span></span></code></pre>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..fcd653e2
--- /dev/null
+++ b/vhosts/blog/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html
@@ -0,0 +1,290 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="Ruby 3.0 で追加される case in 構文と、then キーワードについて。">
+ <meta name="keywords" content="Ruby,Ruby 3">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【Ruby】 then キーワードと case in | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【Ruby】 then キーワードと case in</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/ruby/">Ruby</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/ruby3/">Ruby 3</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+ </ol>
+ </section>
+ <div class="admonition">
+ <div class="admonition-label">
+ NOTE
+ </div>
+ <div class="admonition-content">
+ この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/787a8cf888a304497223">https://qiita.com/nsfisis/items/787a8cf888a304497223</a>
+ </div>
+ </div>
+
+ <section id="section--tl-dr">
+ <h2><a href="#section--tl-dr">TL; DR</a></h2>
+ <p>
+ <code>case</code> - <code>in</code> によるパターンマッチング構文でも、<code>case</code> - <code>when</code> と同じように <code>then</code> が使える (場合によっては使う必要がある)。
+ </p>
+ </section>
+
+ <section id="section--what-is-then-keyword">
+ <h2><a href="#section--what-is-then-keyword"><code>then</code> とは</a></h2>
+ <p>
+ 使われることは稀だが、Ruby では <code>then</code> がキーワードになっている。次のように使う:
+ </p>
+
+ <pre class="highlight" language="ruby" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">if</span> cond <span class="hljs-keyword">then</span>
+ puts <span class="hljs-string">&quot;Y&quot;</span>
+<span class="hljs-keyword">else</span>
+ puts <span class="hljs-string">&quot;N&quot;</span>
+<span class="hljs-keyword">end</span></code></pre>
+
+ <p>
+ このキーワードが現れうる場所はいくつかあり、<code>if</code>、<code>unless</code>、<code>rescue</code>、<code>case</code> 構文がそれに当たる。 上記のように、何か条件を書いた後 <code>then</code> を置き、式がそこで終了していることを示すマーカーとして機能する。
+ </p>
+
+ <pre class="highlight" language="ruby" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment"># Example:</span>
+
+<span class="hljs-keyword">if</span> x <span class="hljs-keyword">then</span>
+ a
+<span class="hljs-keyword">end</span>
+
+<span class="hljs-keyword">unless</span> x <span class="hljs-keyword">then</span>
+ a
+<span class="hljs-keyword">end</span>
+
+<span class="hljs-keyword">begin</span>
+ a
+<span class="hljs-keyword">rescue</span> <span class="hljs-keyword">then</span>
+ b
+<span class="hljs-keyword">end</span>
+
+<span class="hljs-keyword">case</span> x
+<span class="hljs-keyword">when</span> p <span class="hljs-keyword">then</span>
+ a
+<span class="hljs-keyword">end</span></code></pre>
+ </section>
+
+ <section id="section--why-then-is-usually-unnecessary">
+ <h2><a href="#section--why-then-is-usually-unnecessary">なぜ普段は書かなくてもよいのか</a></h2>
+ <p>
+ 普通 Ruby のコードで <code>then</code> を書くことはない。なぜか。次のコードを実行してみるとわかる。
+ </p>
+
+ <pre class="highlight" language="ruby" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">if</span> <span class="hljs-literal">true</span> puts <span class="hljs-string">&#x27;Hello, World!&#x27;</span> <span class="hljs-keyword">end</span></code></pre>
+
+ <p>
+ 次のような構文エラーが出力される。
+ </p>
+
+ <pre class="highlight monospaced"><code>20:1: syntax error, unexpected local variable or method, expecting `then&apos; or &apos;;&apos; or &apos;\n&apos;
+if true puts &apos;Hello, World!&apos; end
+ ^~~~
+20:1: syntax error, unexpected `end&apos;, expecting end-of-input
+...f true puts &apos;Hello, World!&apos; end</code></pre>
+
+ <p>
+ 二つ目のメッセージは無視して一つ目を読むと、<code>then</code> か <code>;</code> か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。
+ </p>
+
+ <p>
+ ポイントは改行が <code>then</code> (や <code>;</code>) の代わりとなることである。<code>true</code> の後に改行を入れてみる。
+ </p>
+
+ <pre class="highlight" language="ruby" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">if</span> <span class="hljs-literal">true</span>
+puts <span class="hljs-string">&#x27;Hello, World!&#x27;</span> <span class="hljs-keyword">end</span></code></pre>
+
+ <p>
+ 無事 Hello, World! と出力されるようになった。
+ </p>
+ </section>
+
+ <section id="section--why-then-or-linebreak-is-needed">
+ <h2><a href="#section--why-then-or-linebreak-is-needed">なぜ <code>then</code> や <code>;</code> や改行が必要か</a></h2>
+ <p>
+ なぜ <code>then</code> や <code>;</code> や改行 (以下 「<code>then</code> 等」) が必要なのだろうか。次の例を見てほしい:
+ </p>
+
+ <pre class="highlight" language="ruby" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">if</span> a b <span class="hljs-keyword">end</span></code></pre>
+
+ <p>
+ <code>then</code> も <code>;</code> も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。 この例は二通りに解釈できる。
+ </p>
+
+ <pre class="highlight" language="ruby" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価</span>
+<span class="hljs-keyword">if</span> a <span class="hljs-keyword">then</span>
+b
+<span class="hljs-keyword">end</span></code></pre>
+
+ <pre class="highlight" language="ruby" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment"># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、</span>
+<span class="hljs-comment"># その結果が truthy なら何もしない</span>
+<span class="hljs-keyword">if</span> a(b) <span class="hljs-keyword">then</span>
+<span class="hljs-keyword">end</span></code></pre>
+
+ <p>
+ <code>then</code> 等はこの曖昧性を排除するためにあり、条件式は <code>if</code> から <code>then</code> 等までの間にある、ということを明確にする。 C系の <code>if</code> 後に来る <code>(</code>/<code>)</code> や、Python の <code>:</code>、Rust/Go/Swift などの <code>{</code> も同じ役割を持つ。
+ </p>
+
+ <p>
+ Ruby の場合、プログラマーが書きやすいよう改行でもって <code>then</code> が代用できるので、ほとんどの場合 <code>then</code> は必要ない。
+ </p>
+ </section>
+
+ <section id="section--then-in-case-in">
+ <h2><a href="#section--then-in-case-in"><code>case</code> - <code>in</code> における <code>then</code></a></h2>
+ <p>
+ ようやく本題にたどり着いた。来る Ruby 3.0 では <code>case</code> と <code>in</code> キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして <code>then</code> 等が必要になる。 (現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。
+ </p>
+
+ <p>
+ <a href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</a>
+ </p>
+
+ <pre class="highlight" language="yacc" linenumbering="unnumbered"><code>p_case_body : keyword_in
+{
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ p-&gt;command_start = FALSE;
+ $&lt;ctxt&gt;1 = p-&gt;ctxt;
+ p-&gt;ctxt.in_kwarg = 1;
+ $&lt;tbl&gt;$ = push_pvtbl(p);
+}
+{
+ $&lt;tbl&gt;$ = push_pktbl(p);
+}
+p_top_expr then
+{
+ pop_pktbl(p, $&lt;tbl&gt;3);
+ pop_pvtbl(p, $&lt;tbl&gt;2);
+ p-&gt;ctxt.in_kwarg = $&lt;ctxt&gt;1.in_kwarg;
+}
+compstmt
+p_cases
+{
+ /*%%%*/
+ $$ = NEW_IN($4, $7, $8, &amp;@$);
+ /*% %*/
+ /*% ripper: in!($4, $7, escape_Qundef($8)) %*/
+}
+;</code></pre>
+
+ <p>
+ 簡略版:
+ </p>
+
+ <pre class="highlight" language="yacc" linenumbering="unnumbered"><code>p_case_body : keyword_in p_top_expr then compstmt p_cases
+;</code></pre>
+
+ <p>
+ ここで、<code>keyword_in</code> は文字通り <code>in</code>、<code>p_top_expr</code> はいわゆるパターン、<code>then</code> は <code>then</code> キーワードのことではなく、この記事で <code>then</code> 等と呼んでいるもの、つまり <code>then</code> キーワード、<code>;</code>、改行のいずれかである。
+ </p>
+
+ <p>
+ これにより、<code>case</code> - <code>when</code> による従来の構文と同じように、<code>then</code> 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:
+ </p>
+
+ <pre class="highlight" language="ruby" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">case</span> x
+<span class="hljs-keyword">in</span> <span class="hljs-number">1</span> <span class="hljs-keyword">then</span> a
+<span class="hljs-keyword">in</span> <span class="hljs-number">2</span> <span class="hljs-keyword">then</span> b
+<span class="hljs-keyword">in</span> <span class="hljs-number">3</span> <span class="hljs-keyword">then</span> c
+<span class="hljs-keyword">end</span>
+
+<span class="hljs-keyword">case</span> x
+<span class="hljs-keyword">in</span> <span class="hljs-number">1</span>
+ a
+<span class="hljs-keyword">in</span> <span class="hljs-number">2</span>
+ b
+<span class="hljs-keyword">in</span> <span class="hljs-number">3</span>
+ c
+<span class="hljs-keyword">end</span>
+
+<span class="hljs-keyword">case</span> x
+<span class="hljs-keyword">in</span> <span class="hljs-number">1</span>; a
+<span class="hljs-keyword">in</span> <span class="hljs-number">2</span>; b
+<span class="hljs-keyword">in</span> <span class="hljs-number">3</span>; c
+<span class="hljs-keyword">end</span></code></pre>
+
+ <p>
+ ところで、<code>p_top_expr</code> には <code>if</code> による guard clause が書けるので、その場合は <code>if</code> - <code>then</code> と似たような見た目になる。
+ </p>
+
+ <pre class="highlight" language="ruby" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">case</span> x
+<span class="hljs-keyword">in</span> <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> a
+<span class="hljs-keyword">in</span> n <span class="hljs-keyword">if</span> n &lt; <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> b
+<span class="hljs-keyword">in</span> n <span class="hljs-keyword">then</span> c
+<span class="hljs-keyword">end</span></code></pre>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">まとめ</a></h2>
+ <ul>
+ <li>
+ <code>if</code> や <code>case</code> の条件の後ろには <code>then</code>、<code>;</code>、改行のいずれかが必要
+ <ul>
+ <li>
+ 通常は改行しておけばよい
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ 3.0 で入る予定の <code>case</code> - <code>in</code> でも <code>then</code> 等が必要になる
+ </li>
+
+ <li>
+ Ruby の構文を正確に知るには (現状) <code>parse.y</code> を直接読めばよい
+ </li>
+ </ul>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..7509e3a0
--- /dev/null
+++ b/vhosts/blog/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html
@@ -0,0 +1,258 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="Rust のプリミティブ型は予約語ではなく普通の識別子である。どのようにこれが名前解決されるのかを調べた。">
+ <meta name="keywords" content="Rust">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>Rust のプリミティブ型はどこからやって来るか | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">Rust のプリミティブ型はどこからやって来るか</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/rust/">Rust</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+ </ol>
+ </section>
+ <div class="admonition">
+ <div class="admonition-label">
+ NOTE
+ </div>
+ <div class="admonition-content">
+ この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</a>
+ </div>
+ </div>
+
+ <section id="section--intro">
+ <h2><a href="#section--intro">前置き</a></h2>
+ <p>
+ Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。
+ </p>
+
+ <pre class="highlight" language="rust" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">#![allow(non_camel_case_types)]</span>
+<span class="hljs-meta">#![allow(dead_code)]</span>
+
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">bool</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">char</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">i8</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">i16</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">i32</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">i64</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">i128</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">isize</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">u8</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">u16</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">u32</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">u64</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">u128</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">usize</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">f32</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">f64</span>;
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">str</span>;</code></pre>
+
+ <p>
+ では、普段単に <code>bool</code> と書いたとき、この <code>bool</code> は一体どこから来ているのか。rustc のソースを追ってみた。
+ </p>
+
+ <blockquote>
+ <p>
+ 前提知識: 一般的なコンパイラの構造、用語。<code>rustc</code> そのものの知識は不要 (というよりも筆者自身がよく知らない)
+ </p>
+ </blockquote>
+ </section>
+
+ <section id="section--code-reading">
+ <h2><a href="#section--code-reading">調査</a></h2>
+ <p>
+ 調査に使用したソース (調査時点での最新 master)
+ </p>
+
+ <p>
+ <a href="https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98">https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98</a>
+ </p>
+
+ <p>
+ どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。
+ </p>
+
+ <p>
+ 大雑把な構造としては、<code>compiler</code> フォルダ以下に <code>rustc_*</code> という名前のクレートが数十個入っている。これがどうやら <code>rustc</code> コマンドの実装部のようだ。
+ </p>
+
+ <p>
+ <code>rustc</code> はセルフホストされている (= <code>rustc</code> 自身が Rust で書かれている) ので、<code>bool</code> や <code>char</code> などで適当に検索をかけてもノイズが多すぎて話にならない。 しかし、お誂え向きなことに <code>i128</code>/<code>u128</code> というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って <code>git grep</code> してみる。
+ </p>
+
+ <pre class="highlight monospaced"><code>$ git grep &quot;\bi128\b&quot; | wc # i128
+165 1069 15790
+
+$ git grep &quot;\bu128\b&quot; | wc # u128
+293 2127 26667
+
+$ git grep &quot;\bbool\b&quot; | wc # cf. bool の結果
+3563 23577 294659</code></pre>
+
+ <p>
+ 165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。
+ </p>
+
+ <pre class="highlight monospaced"><code>$ git grep &quot;\bi128\b&quot;
+...
+rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));
+...</code></pre>
+
+ <p>
+ <code>rustc_resolve</code> というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。
+ </p>
+
+ <pre class="highlight" language="rust" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment">/// Interns the names of the primitive types.</span>
+<span class="hljs-comment">///</span>
+<span class="hljs-comment">/// All other types are defined somewhere and possibly imported, but the primitive ones need</span>
+<span class="hljs-comment">/// special handling, since they have no place of origin.</span>
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">PrimitiveTypeTable</span> {
+ primitive_types: FxHashMap&lt;Symbol, PrimTy&gt;,
+}
+
+<span class="hljs-keyword">impl</span> <span class="hljs-title class_">PrimitiveTypeTable</span> {
+ <span class="hljs-keyword">fn</span> <span class="hljs-title function_">new</span>() <span class="hljs-punctuation">-&gt;</span> PrimitiveTypeTable {
+ <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut </span><span class="hljs-variable">table</span> = FxHashMap::<span class="hljs-title function_ invoke__">default</span>();
+
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">bool</span>, Bool);
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">char</span>, Char);
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">f32</span>, <span class="hljs-title function_ invoke__">Float</span>(FloatTy::F32));
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">f64</span>, <span class="hljs-title function_ invoke__">Float</span>(FloatTy::F64));
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">isize</span>, <span class="hljs-title function_ invoke__">Int</span>(IntTy::Isize));
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">i8</span>, <span class="hljs-title function_ invoke__">Int</span>(IntTy::I8));
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">i16</span>, <span class="hljs-title function_ invoke__">Int</span>(IntTy::I16));
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">i32</span>, <span class="hljs-title function_ invoke__">Int</span>(IntTy::I32));
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">i64</span>, <span class="hljs-title function_ invoke__">Int</span>(IntTy::I64));
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">i128</span>, <span class="hljs-title function_ invoke__">Int</span>(IntTy::I128));
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">str</span>, Str);
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">usize</span>, <span class="hljs-title function_ invoke__">Uint</span>(UintTy::Usize));
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">u8</span>, <span class="hljs-title function_ invoke__">Uint</span>(UintTy::U8));
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">u16</span>, <span class="hljs-title function_ invoke__">Uint</span>(UintTy::U16));
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">u32</span>, <span class="hljs-title function_ invoke__">Uint</span>(UintTy::U32));
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">u64</span>, <span class="hljs-title function_ invoke__">Uint</span>(UintTy::U64));
+ table.<span class="hljs-title function_ invoke__">insert</span>(sym::<span class="hljs-type">u128</span>, <span class="hljs-title function_ invoke__">Uint</span>(UintTy::U128));
+ <span class="hljs-keyword">Self</span> { primitive_types: table }
+ }
+}</code></pre>
+
+ <p>
+ これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、
+ </p>
+
+ <blockquote>
+ <p>
+ All other types are defined somewhere and possibly imported, but the primitive ones need special handling, since they have no place of origin.
+ </p>
+ </blockquote>
+
+ <p>
+ とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。
+ </p>
+
+ <pre class="highlight" language="rust" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment">/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.</span>
+<span class="hljs-comment">/// (略)</span>
+<span class="hljs-keyword">fn</span> <span class="hljs-title function_">resolve_ident_in_lexical_scope</span>(
+ &amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>,
+ <span class="hljs-keyword">mut</span> ident: Ident,
+ ns: Namespace,
+ <span class="hljs-comment">// (略)</span>
+) <span class="hljs-punctuation">-&gt;</span> <span class="hljs-type">Option</span>&lt;LexicalScopeBinding&lt;<span class="hljs-symbol">&#x27;a</span>&gt;&gt; {
+ <span class="hljs-comment">// (略)</span>
+
+ <span class="hljs-keyword">if</span> ns == TypeNS {
+ <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-variable">Some</span>(prim_ty) = <span class="hljs-keyword">self</span>.primitive_type_table.primitive_types.<span class="hljs-title function_ invoke__">get</span>(&amp;ident.name) {
+ <span class="hljs-keyword">let</span> <span class="hljs-variable">binding</span> =
+ (Res::<span class="hljs-title function_ invoke__">PrimTy</span>(*prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::<span class="hljs-title function_ invoke__">root</span>())
+ .<span class="hljs-title function_ invoke__">to_name_binding</span>(<span class="hljs-keyword">self</span>.arenas);
+ <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">Some</span>(LexicalScopeBinding::<span class="hljs-title function_ invoke__">Item</span>(binding));
+ }
+ }
+
+ <span class="hljs-literal">None</span>
+}</code></pre>
+
+ <p>
+ 関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。 <code>if ns == TypeNS</code> のブロック内では、<code>primitive_type_table</code> (上記の <code>PrimitiveTypeTable::new()</code> で作られた変数) に含まれている識別子 (<code>bool</code>、<code>i32</code> など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。
+ </p>
+
+ <p>
+ なお、<code>ns</code> は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この <code>if</code> は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。
+ </p>
+
+ <p>
+ 重要なのは、これが <code>resolve_ident_in_lexical_scope()</code> の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。
+ </p>
+
+ <p>
+ 動作がわかったところで、例として次のコードを考える。
+ </p>
+
+ <pre class="highlight" language="rust" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">#![allow(non_camel_case_types)]</span>
+
+<span class="hljs-keyword">struct</span> <span class="hljs-title class_">bool</span>;
+
+<span class="hljs-keyword">fn</span> <span class="hljs-title function_">main</span>() {
+ <span class="hljs-keyword">let</span> <span class="hljs-variable">_</span>: <span class="hljs-type">bool</span> = <span class="hljs-type">bool</span>;
+}</code></pre>
+
+ <p>
+ ここで <code>main()</code> の <code>bool</code> は <code>struct bool</code> として解決される。なぜなら、プリミティブ型の判定をする前に <code>bool</code> という名前の別の型が見つかるからだ。
+ </p>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">まとめ</a></h2>
+ <p>
+ Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..ea874004
--- /dev/null
+++ b/vhosts/blog/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html
@@ -0,0 +1,224 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、違いはないことがわかった。">
+ <meta name="keywords" content="Vim">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【Vim】 autocmd events の BufWrite/BufWritePre の違い | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【Vim】 autocmd events の BufWrite/BufWritePre の違い</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/vim/">Vim</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+ </ol>
+ </section>
+ <div class="admonition">
+ <div class="admonition-label">
+ NOTE
+ </div>
+ <div class="admonition-content">
+ この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/79ab4db8564032de0b25">https://qiita.com/nsfisis/items/79ab4db8564032de0b25</a>
+ </div>
+ </div>
+
+ <section id="section--tl-dr">
+ <h2><a href="#section--tl-dr">TL; DR</a></h2>
+ <p>
+ 違いはない。ただのエイリアス。
+ </p>
+ </section>
+
+ <section id="section--code-reading">
+ <h2><a href="#section--code-reading">調査記録</a></h2>
+ <p>
+ Vim の autocmd events には似通った名前のものがいくつかある。大抵は <code>:help</code> に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。
+ </p>
+
+ <ul>
+ <li>
+ <code>BufRead</code>/<code>BufReadPost</code>
+ </li>
+
+ <li>
+ <code>BufWrite</code>/<code>BufWritePre</code>
+ </li>
+
+ <li>
+ <code>BufAdd</code>/<code>BufCreate</code>
+ </li>
+ </ul>
+
+ <p>
+ このうち、<code>BufAdd</code>/<code>BufCreate</code> に関しては、<code>:help BufCreate</code> に
+ </p>
+
+ <blockquote>
+ <p>
+ The BufCreate event is for historic reasons.
+ </p>
+ </blockquote>
+
+ <p>
+ とあり、おそらくは <code>BufAdd</code> のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため vim と neovim のソースコードを調査した。
+ </p>
+
+ <blockquote>
+ <p>
+ ソースコードへのリンク <a href="https://github.com/vim/vim/tree/8e6be34338f13a6a625f19bcef82019c9adc65f2">vim (調査時点での master branch)</a> <a href="https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3">neovim (上に同じ)</a>
+ </p>
+ </blockquote>
+
+ <section id="section--code-reading--vim">
+ <h3><a href="#section--code-reading--vim">vim のソースコード</a></h3>
+ <p>
+ 以下は、autocmd events の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。
+ </p>
+
+ <p>
+ <a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86</a>
+ </p>
+
+ <pre class="highlight" language="c" linenumbering="unnumbered"><code class="highlight">{<span class="hljs-string">&quot;BufAdd&quot;</span>, EVENT_BUFADD},
+{<span class="hljs-string">&quot;BufCreate&quot;</span>, EVENT_BUFADD},</code></pre>
+
+ <p>
+ <a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97</a>
+ </p>
+
+ <pre class="highlight" language="c" linenumbering="unnumbered"><code class="highlight">{<span class="hljs-string">&quot;BufRead&quot;</span>, EVENT_BUFREADPOST},
+{<span class="hljs-string">&quot;BufReadCmd&quot;</span>, EVENT_BUFREADCMD},
+{<span class="hljs-string">&quot;BufReadPost&quot;</span>, EVENT_BUFREADPOST},</code></pre>
+
+ <p>
+ <a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105</a>
+ </p>
+
+ <pre class="highlight" language="c" linenumbering="unnumbered"><code class="highlight">{<span class="hljs-string">&quot;BufWrite&quot;</span>, EVENT_BUFWRITEPRE},
+{<span class="hljs-string">&quot;BufWritePost&quot;</span>, EVENT_BUFWRITEPOST},
+{<span class="hljs-string">&quot;BufWritePre&quot;</span>, EVENT_BUFWRITEPRE},</code></pre>
+ </section>
+
+ <section id="section--code-reading--neovim">
+ <h3><a href="#section--code-reading--neovim">neovim のソースコード</a></h3>
+ <p>
+ neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua で書かれている。以下にある通り、はっきり <code>aliases</code> と書かれている。
+ </p>
+
+ <p>
+ <a href="https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124">https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124</a>
+ </p>
+
+ <pre class="highlight" language="lua" linenumbering="unnumbered"><code class="highlight">aliases = {
+BufCreate = <span class="hljs-string">&#x27;BufAdd&#x27;</span>,
+BufRead = <span class="hljs-string">&#x27;BufReadPost&#x27;</span>,
+BufWrite = <span class="hljs-string">&#x27;BufWritePre&#x27;</span>,
+FileEncoding = <span class="hljs-string">&#x27;EncodingChanged&#x27;</span>,
+},</code></pre>
+
+ <p>
+ ところで、上では取り上げなかった <code>FileEncoding</code> だが、これは <code>:help FileEncoding</code> にしっかりと書いてある。
+ </p>
+
+ <pre class="highlight monospaced"><code> *FileEncoding*
+FileEncoding Obsolete. It still works and is equivalent
+ to |EncodingChanged|.</code></pre>
+ </section>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">まとめ</a></h2>
+ <p>
+ 記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。
+ </p>
+
+ <ul>
+ <li>
+ <code>BufAdd</code>/<code>BufCreate</code>
+ <ul>
+ <li>
+ → <code>BufCreate</code> は歴史的な理由により (&quot;for historic reasons&quot;) 存在しているため、新しい方 (<code>BufAdd</code>) を使う
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ <code>BufRead</code>/<code>BufReadPost</code>
+ <ul>
+ <li>
+ → <code>BufReadPre</code> との対称性のため、あるいは <code>BufWritePost</code> との対称性のため <code>BufReadPost</code> を使う
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ <code>BufWrite</code>/<code>BufWritePre</code>
+ <ul>
+ <li>
+ → <code>BufWritePost</code> との対称性のため、あるいは <code>BufReadPre</code> との対称性のため <code>BufWritePre</code> を使う
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ <code>FileEncoding</code>/<code>EncodingChanged</code>
+ <ul>
+ <li>
+ → <code>FileEncoding</code> は <code>`Obsolete&apos;&apos; と明言されているので、`EncodingChanged</code> を使う
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>
+ ところでこの調査で知ったのだが、<code>BufRead</code> と <code>BufWrite</code> は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら <code>Pre</code>/<code>Post</code> 付きのものを使った方が分かりやすいだろう。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..9ca04808
--- /dev/null
+++ b/vhosts/blog/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html
@@ -0,0 +1,253 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="Vim で選択した行の順番を入れ替える方法。">
+ <meta name="keywords" content="Vim">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>Vimで選択した行の順番を入れ替える | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">Vimで選択した行の順番を入れ替える</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/vim/">Vim</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+ </ol>
+ </section>
+ <div class="admonition">
+ <div class="admonition-label">
+ NOTE
+ </div>
+ <div class="admonition-content">
+ この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/4fefb361d9a693803520">https://qiita.com/nsfisis/items/4fefb361d9a693803520</a>
+ </div>
+ </div>
+
+ <section id="section--tl-dr">
+ <h2><a href="#section--tl-dr">TL; DR</a></h2>
+ <pre class="highlight" language="vim" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment">&quot; License: Public Domain</span>
+
+command! -bar -<span class="hljs-built_in">range</span>=%
+ \ Reverse
+ \ keeppatterns <span class="hljs-symbol">&lt;line1&gt;</span>,<span class="hljs-symbol">&lt;line2&gt;</span>g/^/<span class="hljs-keyword">m</span><span class="hljs-symbol">&lt;line1&gt;</span>-<span class="hljs-number">1</span></code></pre>
+ </section>
+
+ <section id="section--version">
+ <h2><a href="#section--version">バージョン情報</a></h2>
+ <p>
+ <code>:version</code> の一部
+ </p>
+
+ <blockquote>
+ <p>
+ VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Jan 26 2020 11:30:30) macOS version Included patches: 1-148 Huge version without GUI.
+ </p>
+ </blockquote>
+ </section>
+
+ <section id="section--existing-solution">
+ <h2><a href="#section--existing-solution">よく紹介されている手法</a></h2>
+ <section id="section--existing-solution--external-commands">
+ <h3><a href="#section--existing-solution--external-commands"><code>tac</code> / <code>tail</code></a></h3>
+ <p>
+ <code>tac</code> や <code>tail -r</code> などの外部コマンドを <code>!</code> を使って呼び出し、置き換える。
+ </p>
+
+ <blockquote>
+ <p>
+ :h v_!
+ </p>
+ </blockquote>
+
+ <p>
+ <code>tac</code> コマンドや <code>tail</code> の <code>-r</code> オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい
+ </p>
+ </section>
+
+ <section id="section--existing-solution--global-command">
+ <h3><a href="#section--existing-solution--global-command"><code>:g/^/m0</code></a></h3>
+ <p>
+ こちらは外部コマンドに頼らず、Vim の機能のみを使う。<code>g</code> は <code>:global</code> コマンドの、<code>m</code> は <code>:move</code> コマンドの略
+ </p>
+
+ <p>
+ <code>:global</code> コマンドは <code>:[range]global/{pattern}/[command]</code> のように使い、<code>[range]</code> で指定された範囲の行のうち、<code>{pattern}</code> で指定された検索パターンにマッチする行に対して、順番に <code>[command]</code> で指定された Ex コマンドを呼び出す。
+ </p>
+
+ <blockquote>
+ <p>
+ :h :global
+ </p>
+ </blockquote>
+
+ <p>
+ <code>:move</code> コマンドは <code>[range]:move {address}</code> のように使い、<code>[range]</code> で指定された範囲の行を <code>{address}</code> で指定された位置に移動させる。
+ </p>
+
+ <blockquote>
+ <p>
+ :h :move
+ </p>
+ </blockquote>
+
+ <p>
+ <code>:g/^/m0</code> のように組み合わせると、「すべての行を1行ずつ 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。
+ </p>
+
+ <p>
+ なお、<code>:g/^/m0</code> は全ての行を入れ替えるが、<code>:N,Mg/^/mN-1</code> とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。
+ </p>
+
+ <pre class="highlight" language="vim" linenumbering="unnumbered"><code class="highlight">command! -bar -<span class="hljs-built_in">range</span>=%
+ \ Reverse
+ \ <span class="hljs-symbol">&lt;line1&gt;</span>,<span class="hljs-symbol">&lt;line2&gt;</span>g/^/<span class="hljs-keyword">m</span><span class="hljs-symbol">&lt;line1&gt;</span>-<span class="hljs-number">1</span></code></pre>
+
+ <p>
+ これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。
+ </p>
+ </section>
+ </section>
+
+ <section id="section--problem-of-global-command">
+ <h2><a href="#section--problem-of-global-command"><code>:g/^/m0</code> の問題点</a></h2>
+ <p>
+ <code>:global</code> コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。<code>^</code> は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。<code>&apos;hlsearch&apos;</code> オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと <code>n</code> コマンドなどの際に不便である。
+ </p>
+
+ <blockquote>
+ <p>
+ :h @/
+ </p>
+ </blockquote>
+ </section>
+
+ <section id="section--solution">
+ <h2><a href="#section--solution">解決策</a></h2>
+ <blockquote>
+ <p>
+ [2020/9/28追記] より簡潔な方法を見つけたので次節に追記した
+ </p>
+ </blockquote>
+
+ <p>
+ 前述した <code>:Reverse</code> コマンドの定義を少し変えて、次のようにする:
+ </p>
+
+ <pre class="highlight" language="vim" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">function!</span> <span class="hljs-title">s</span>:reverse_lines<span class="hljs-params">(from, to)</span> abort
+ <span class="hljs-keyword">execute</span> <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%d,%dg/^/m%d&quot;</span>, <span class="hljs-variable">a:from</span>, <span class="hljs-variable">a:to</span>, <span class="hljs-variable">a:from</span> - <span class="hljs-number">1</span>)
+<span class="hljs-keyword">endfunction</span>
+
+command! -bar -<span class="hljs-built_in">range</span>=%
+ \ Reverse
+ \ <span class="hljs-keyword">call</span> <span class="hljs-symbol">&lt;SID&gt;</span>reverse_lines(<span class="hljs-symbol">&lt;line1&gt;</span>, <span class="hljs-symbol">&lt;line2&gt;</span>)</code></pre>
+
+ <p>
+ 実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。
+ </p>
+
+ <p>
+ この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが <code>^</code> で上書きされることがなくなる。
+ </p>
+
+ <p>
+ Vim のヘルプから該当箇所を引用する (強調は筆者による)。
+ </p>
+
+ <blockquote>
+ <p>
+ :h autocmd-searchpat
+ </p>
+
+ <p>
+ <em role="strong">Autocommands do not change the current search patterns.</em> Vim saves the current search patterns before executing autocommands then restores them after the autocommands finish. This means that autocommands do not affect the strings highlighted with the `hlsearch&apos; option.
+ </p>
+ </blockquote>
+
+ <p>
+ これは autocommand の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは <code>:nohlsearch</code> のヘルプにある。同じく該当箇所を引用する (強調は筆者による)。
+ </p>
+
+ <blockquote>
+ <p>
+ :h :nohlsearch
+ </p>
+
+ <p>
+ (略) This command doesn’t work in an autocommand, because the highlighting state is saved and restored when executing autocommands |autocmd-searchpat|. <em role="strong">Same thing for when invoking a user function.</em>
+ </p>
+ </blockquote>
+
+ <p>
+ この仕様により、<code>:g/^/m0</code> の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。
+ </p>
+ </section>
+
+ <section id="section--solution-revised">
+ <h2><a href="#section--solution-revised">解決策 (改訂版)</a></h2>
+ <blockquote>
+ <p>
+ [2020/9/28追記] より簡潔な方法を見つけたため追記する
+ </p>
+ </blockquote>
+
+ <pre class="highlight" language="vim" linenumbering="unnumbered"><code class="highlight">command! -bar -<span class="hljs-built_in">range</span>=%
+ \ Reverse
+ \ keeppatterns <span class="hljs-symbol">&lt;line1&gt;</span>,<span class="hljs-symbol">&lt;line2&gt;</span>g/^/<span class="hljs-keyword">m</span><span class="hljs-symbol">&lt;line1&gt;</span>-<span class="hljs-number">1</span></code></pre>
+
+ <p>
+ まさにこのための Exコマンド、<code>:keeppatterns</code> が存在する。<code>:keeppatterns {command}</code> のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。
+ </p>
+
+ <blockquote>
+ <p>
+ :h :keeppatterns
+ </p>
+ </blockquote>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..b19f038d
--- /dev/null
+++ b/vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html
@@ -0,0 +1,605 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2022 nsfisis">
+ <meta name="description" content="PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。">
+ <meta name="keywords" content="カンファレンス,PHP,PHPerKaigi">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHPerKaigi 2022 トークン問題の解説 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHPerKaigi 2022 トークン問題の解説</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/conference/">カンファレンス</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/phperkaigi/">PHPerKaigi</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2022-04-09">2022-04-09</time>: 公開
+ </li>
+ <li class="revision">
+ <time datetime="2022-04-16">2022-04-16</time>: 2問目、3問目の解説を追加、1問目に加筆
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ 本日開始された <a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> の PHPer チャレンジにおいて、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。
+ </p>
+
+ <p>
+ リポジトリはこちら: <a href="https://github.com/nsfisis/PHPerKaigi2022-tokens">https://github.com/nsfisis/PHPerKaigi2022-tokens</a>
+ </p>
+ </section>
+
+ <section id="section--q1-brainfuck">
+ <h2><a href="#section--q1-brainfuck">第1問 brainf_ck.php</a></h2>
+ <p>
+ ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+
+<span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">0O1</span>);
+
+<span class="hljs-keyword">namespace</span> <span class="hljs-title class_">Dgcircus</span>\<span class="hljs-title class_">PHPerKaigi</span>\<span class="hljs-title class_">Y2022</span>;
+
+<span class="hljs-comment">/**
+ * <span class="hljs-doctag">@todo</span>
+ * Run this program to acquire a PHPer token.
+ */</span>
+
+https:<span class="hljs-comment">//creativecommons.org/publicdomain/zero/1.0/</span>
+
+\<span class="hljs-title function_ invoke__">error_reporting</span>(~+!<span class="hljs-string">&#x27;We are hiring!&#x27;</span>);
+
+<span class="hljs-variable">$z</span> = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$f</span></span>) =&gt;</span> (<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$x</span></span>) =&gt;</span> <span class="hljs-variable">$f</span>(<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params">...<span class="hljs-variable">$xs</span></span>) =&gt;</span> <span class="hljs-variable">$x</span>(<span class="hljs-variable">$x</span>)(...<span class="hljs-variable">$xs</span>)))(<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$x</span></span>) =&gt;</span> <span class="hljs-variable">$f</span>(<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params">...<span class="hljs-variable">$xs</span></span>) =&gt;</span> <span class="hljs-variable">$x</span>(<span class="hljs-variable">$x</span>)(...<span class="hljs-variable">$xs</span>)));
+<span class="hljs-variable">$id</span> = \<span class="hljs-title function_ invoke__">spl_object_id</span>(...);
+<span class="hljs-variable">$put</span> = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$c</span></span>) =&gt;</span> \<span class="hljs-title function_ invoke__">printf</span>(<span class="hljs-string">&#x27;%c&#x27;</span>, <span class="hljs-variable">$c</span>);
+<span class="hljs-variable">$mm</span> = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$p</span>, <span class="hljs-variable">$n</span></span>) =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">\ArrayObject</span>(\<span class="hljs-title function_ invoke__">array_fill</span>(+!![], <span class="hljs-variable">$n</span>, <span class="hljs-variable">$p</span>));
+
+$👉 = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$m</span>, <span class="hljs-variable">$p</span>, <span class="hljs-variable">$b</span>, <span class="hljs-variable">$e</span>, <span class="hljs-variable">$mp</span>, <span class="hljs-variable">$pc</span></span>) =&gt;</span> [++<span class="hljs-variable">$mp</span>, ++<span class="hljs-variable">$pc</span>];
+$👈 = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$m</span>, <span class="hljs-variable">$p</span>, <span class="hljs-variable">$b</span>, <span class="hljs-variable">$e</span>, <span class="hljs-variable">$mp</span>, <span class="hljs-variable">$pc</span></span>) =&gt;</span> [--<span class="hljs-variable">$mp</span>, ++<span class="hljs-variable">$pc</span>];
+$👍 = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$m</span>, <span class="hljs-variable">$p</span>, <span class="hljs-variable">$b</span>, <span class="hljs-variable">$e</span>, <span class="hljs-variable">$mp</span>, <span class="hljs-variable">$pc</span></span>) =&gt;</span> [<span class="hljs-variable">$mp</span>, ++<span class="hljs-variable">$pc</span>, ++<span class="hljs-variable">$m</span>[<span class="hljs-variable">$mp</span>]];
+$👎 = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$m</span>, <span class="hljs-variable">$p</span>, <span class="hljs-variable">$b</span>, <span class="hljs-variable">$e</span>, <span class="hljs-variable">$mp</span>, <span class="hljs-variable">$pc</span></span>) =&gt;</span> [<span class="hljs-variable">$mp</span>, ++<span class="hljs-variable">$pc</span>, --<span class="hljs-variable">$m</span>[<span class="hljs-variable">$mp</span>]];
+$📝 = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$m</span>, <span class="hljs-variable">$p</span>, <span class="hljs-variable">$b</span>, <span class="hljs-variable">$e</span>, <span class="hljs-variable">$mp</span>, <span class="hljs-variable">$pc</span></span>) =&gt;</span> [<span class="hljs-variable">$mp</span>, ++<span class="hljs-variable">$pc</span>, <span class="hljs-variable">$put</span>(<span class="hljs-variable">$m</span>[<span class="hljs-variable">$mp</span>])];
+$🤡 = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$m</span>, <span class="hljs-variable">$p</span>, <span class="hljs-variable">$b</span>, <span class="hljs-variable">$e</span>, <span class="hljs-variable">$mp</span>, <span class="hljs-variable">$pc</span></span>) =&gt;</span> <span class="hljs-keyword">match</span> (<span class="hljs-variable">$m</span>[<span class="hljs-variable">$mp</span>]) {
+ +!![] =&gt; [<span class="hljs-variable">$mp</span>, <span class="hljs-variable">$z</span>(<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$loop</span></span>) =&gt;</span> <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$pc</span>, <span class="hljs-variable">$n</span></span>) =&gt;</span> <span class="hljs-keyword">match</span> (<span class="hljs-variable">$id</span>(<span class="hljs-variable">$p</span>[<span class="hljs-variable">$pc</span>])) {
+ <span class="hljs-variable">$b</span> =&gt; <span class="hljs-variable">$loop</span>(++<span class="hljs-variable">$pc</span>, ++<span class="hljs-variable">$n</span>),
+ <span class="hljs-variable">$e</span> =&gt; <span class="hljs-variable">$n</span> === +!![] ? ++<span class="hljs-variable">$pc</span> : <span class="hljs-variable">$loop</span>(++<span class="hljs-variable">$pc</span>, --<span class="hljs-variable">$n</span>),
+ <span class="hljs-keyword">default</span> =&gt; <span class="hljs-variable">$loop</span>(++<span class="hljs-variable">$pc</span>, <span class="hljs-variable">$n</span>),
+ })(<span class="hljs-variable">$pc</span>, -![])],
+ <span class="hljs-keyword">default</span> =&gt; [<span class="hljs-variable">$mp</span>, ++<span class="hljs-variable">$pc</span>],
+};
+$🎪 = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$m</span>, <span class="hljs-variable">$p</span>, <span class="hljs-variable">$b</span>, <span class="hljs-variable">$e</span>, <span class="hljs-variable">$mp</span>, <span class="hljs-variable">$pc</span></span>) =&gt;</span> <span class="hljs-keyword">match</span> (<span class="hljs-variable">$m</span>[<span class="hljs-variable">$mp</span>]) {
+ +!![] =&gt; [<span class="hljs-variable">$mp</span>, ++<span class="hljs-variable">$pc</span>],
+ <span class="hljs-keyword">default</span> =&gt; [<span class="hljs-variable">$mp</span>, <span class="hljs-variable">$z</span>(<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$loop</span></span>) =&gt;</span> <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$pc</span>, <span class="hljs-variable">$n</span></span>) =&gt;</span> <span class="hljs-keyword">match</span> (<span class="hljs-variable">$id</span>(<span class="hljs-variable">$p</span>[<span class="hljs-variable">$pc</span>])) {
+ <span class="hljs-variable">$e</span> =&gt; <span class="hljs-variable">$loop</span>(--<span class="hljs-variable">$pc</span>, ++<span class="hljs-variable">$n</span>),
+ <span class="hljs-variable">$b</span> =&gt; <span class="hljs-variable">$n</span> === +!![] ? <span class="hljs-variable">$pc</span>+![] : <span class="hljs-variable">$loop</span>(--<span class="hljs-variable">$pc</span>, --<span class="hljs-variable">$n</span>),
+ <span class="hljs-keyword">default</span> =&gt; <span class="hljs-variable">$loop</span>(--<span class="hljs-variable">$pc</span>, <span class="hljs-variable">$n</span>),
+ })(<span class="hljs-variable">$pc</span>, -![])],
+};
+$🐘 = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$p</span></span>) =&gt;</span> <span class="hljs-variable">$z</span>(<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$loop</span></span>) =&gt;</span> <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$m</span>, <span class="hljs-variable">$p</span>, <span class="hljs-variable">$b</span>, <span class="hljs-variable">$e</span>, <span class="hljs-variable">$mp</span>, <span class="hljs-variable">$pc</span></span>) =&gt;</span>
+ <span class="hljs-keyword">isset</span>(<span class="hljs-variable">$p</span>[<span class="hljs-variable">$pc</span>]) &amp;&amp; <span class="hljs-variable">$loop</span>(<span class="hljs-variable">$m</span>, <span class="hljs-variable">$p</span>, <span class="hljs-variable">$b</span>, <span class="hljs-variable">$e</span>, ...(<span class="hljs-variable">$p</span>[<span class="hljs-variable">$pc</span>](<span class="hljs-variable">$m</span>, <span class="hljs-variable">$p</span>, <span class="hljs-variable">$b</span>, <span class="hljs-variable">$e</span>, <span class="hljs-variable">$mp</span>, <span class="hljs-variable">$pc</span>)))
+)(<span class="hljs-variable">$mm</span>(+!![], +(![].![])), <span class="hljs-variable">$p</span>, <span class="hljs-variable">$id</span>($🤡), <span class="hljs-variable">$id</span>($🎪), +!![], +!![]);
+
+$🐘([
+ $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
+ $🤡,
+ $👉, $👍, $👍, $👍,
+ $👉, $👍, $👍, $👍, $👍, $👍,
+ $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
+ $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
+ $👈, $👈, $👈, $👈, $👎,
+ $🎪,
+ $👉, $👍, $👍, $👍, $👍, $👍, $📝,
+ $👎, $👎, $📝,
+ $👉, $👎, $👎, $👎, $📝,
+ $👉, $👎, $👎, $👎, $📝,
+ $👎, $👎, $📝,
+ $👎, $📝,
+ $👈, $📝,
+ $👉, $👉, $👎, $👎, $📝,
+ $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝,
+ $👈, $👎, $👎, $👎, $👎, $📝,
+ $👈, $📝,
+ $👉, $👍, $👍, $📝,
+ $👉, $👎, $📝,
+ $👈, $📝,
+]);</code></pre>
+
+ <p>
+ この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。
+ </p>
+
+ <section id="section--q1-brainfuck--commentary">
+ <h3><a href="#section--q1-brainfuck--commentary">解説</a></h3>
+ <section id="section--q1-brainfuck--commentary--emoji">
+ <h4><a href="#section--q1-brainfuck--commentary--emoji">絵文字</a></h4>
+ <p>
+ まず目につくのは大量の絵文字だろう。 PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。
+ </p>
+ </section>
+
+ <section id="section--q1-brainfuck--commentary--brainfuck">
+ <h4><a href="#section--q1-brainfuck--commentary--brainfuck">プログラム全体</a></h4>
+ <p>
+ Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。
+ </p>
+
+ <p>
+ <a href="https://ja.wikipedia.org/wiki/Brainfuck">https://ja.wikipedia.org/wiki/Brainfuck</a>
+ </p>
+
+ <p>
+ なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。
+ </p>
+
+ <pre class="highlight monospaced"><code>+ + + + + + + + + +
+[
+ &gt; + + +
+ &gt; + + + + +
+ &gt; + + + + + + + + + + + +
+ &gt; + + + + + + + + + +
+ &lt; &lt; &lt; &lt; -
+]
+&gt; + + + + + .
+- - .
+&gt; - - - .
+&gt; - - - .
+- - .
+- .
+&lt; .
+&gt; &gt; - - .
++ + + + + + + .
+&lt; - - - - .
+&lt; .
+&gt; + + .
+&gt; - .
+&lt; .</code></pre>
+
+ <p>
+ 実行結果はこちら: <a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a>
+ </p>
+
+ <p>
+ それぞれの絵文字で表された関数が、各命令に対応している。
+ </p>
+
+ <ul>
+ <li>
+ <code>$👉</code>: <code>&gt;</code>
+ </li>
+
+ <li>
+ <code>$👈</code>: <code>&lt;</code>
+ </li>
+
+ <li>
+ <code>$👍</code>: <code>+</code>
+ </li>
+
+ <li>
+ <code>$👎</code>: <code>-</code>
+ </li>
+
+ <li>
+ <code>$📝</code>: <code>.</code>
+ </li>
+
+ <li>
+ <code>$🤡</code>: <code>[</code>
+ </li>
+
+ <li>
+ <code>$🎪</code>: <code>]</code>
+ </li>
+ </ul>
+
+ <p>
+ <code>,</code> (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。
+ </p>
+
+ <p>
+ なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。
+ </p>
+ </section>
+
+ <section id="section--q1-brainfuck--commentary--emoji-selection">
+ <h4><a href="#section--q1-brainfuck--commentary--emoji-selection">絵文字の選択</a></h4>
+ <p>
+ おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> は弊社デジタルサーカスにちなんでいる。 また、<code>$🐘</code> は PHP のマスコットの象に由来する。
+ </p>
+ </section>
+
+ <section id="section--q1-brainfuck--commentary--strict-types">
+ <h4><a href="#section--q1-brainfuck--commentary--strict-types">strict_types</a></h4>
+ <p>
+ <code>declare</code> 文の <code>strict_types</code> に指定できるのは、<code>0</code> か <code>1</code> の数値リテラルだが、 <code>0x0</code> や <code>0b1</code> のような値も受け付ける。 今回は、PHP 8.1 から追加された、<code>0O</code> または <code>0o</code> から始まる八進数リテラルを使った。
+ </p>
+ </section>
+
+ <section id="section--q1-brainfuck--commentary--url">
+ <h4><a href="#section--q1-brainfuck--commentary--url">URL</a></h4>
+ <p>
+ ソースコードのライセンスを示したこの部分だが、
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">https:<span class="hljs-comment">//creativecommons.org/publicdomain/zero/1.0/</span></code></pre>
+
+ <p>
+ 完全に合法な PHP のコードである。 <code>https:</code> 部分はラベル、<code>//</code> 以降は行コメントになっている。
+ </p>
+ </section>
+
+ <section id="section--q1-brainfuck--commentary--numbers">
+ <h4><a href="#section--q1-brainfuck--commentary--numbers">リテラルなしで数値を生成する</a></h4>
+ <p>
+ ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 PHP では、型変換を利用することで任意の整数を作り出すことができる。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-title function_ invoke__">assert</span>(<span class="hljs-number">0</span> === +!![]);
+<span class="hljs-title function_ invoke__">assert</span>(<span class="hljs-number">1</span> === +![]);
+<span class="hljs-title function_ invoke__">assert</span>(<span class="hljs-number">2</span> === ![]+![]);
+<span class="hljs-title function_ invoke__">assert</span>(<span class="hljs-number">3</span> === ![]+![]+![]);
+<span class="hljs-title function_ invoke__">assert</span>(<span class="hljs-number">10</span> === +(![].+!![]));</code></pre>
+
+ <p>
+ <code>[]</code> に <code>!</code> を適用すると <code>true</code> が返ってくる。それに <code>+</code> を適用すると、<code>bool</code> から <code>int</code> ヘの型変換が走り、<code>1</code> が生成される。<code>10</code> はさらにトリッキーだ。まず <code>1</code> と <code>0</code> を作り、<code>.</code> で文字列として結合する (<code>&apos;10&apos;</code>)。これに <code>+</code> を適用すると、<code>string</code> から <code>int</code> への型変換が走り、<code>10</code> が生まれる (コード量に頓着しないなら、<code>1</code> を 10 個足し合わせてももちろん 10 が作れる)。
+ </p>
+
+ <p>
+ また、<code>error_reporting</code> に指定しているのは <code>-1</code> である。 これは、<code>!</code> によって文字列を <code>false</code> にし、<code>+</code> によって <code>false</code> を <code>0</code> にし、さらにビット反転して <code>-1</code> にしている。
+ </p>
+ </section>
+
+ <section id="section--q1-brainfuck--commentary--conditionals">
+ <h4><a href="#section--q1-brainfuck--commentary--conditionals"><code>if</code> 文なしで条件分岐</a></h4>
+ <p>
+ 三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> を一切書かずに条件分岐ができる。 また、<code>&amp;&amp;</code> / <code>||</code> も使えることがある。 遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code> のような形で分岐することもできる。
+ </p>
+ </section>
+
+ <section id="section--q1-brainfuck--commentary--loops">
+ <h4><a href="#section--q1-brainfuck--commentary--loops"><code>while</code>、<code>for</code> 文なしでループ</a></h4>
+ <p>
+ 不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。 ここでは、一般に Z コンビネータとして知られるものを使った (<code>$z</code>)。
+ </p>
+
+ <p>
+ 実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。
+ </p>
+
+ <p>
+ なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、 あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。
+ </p>
+ </section>
+ </section>
+ </section>
+
+ <section id="section--q2-riddle">
+ <h2><a href="#section--q2-riddle">第2問 riddle.php</a></h2>
+ <p>
+ ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+
+<span class="hljs-comment">/*********************************************************
+* This program displays a PHPer token. *
+* Guess &#x27;N&#x27;. *
+* *
+* Hints: *
+* - N itself has no special meaning, e.g., 42, 8128, *
+* it is selected at random. *
+* - Each element of $token represents a single letter. *
+* - One letter consists of 5x5 cells. *
+* - Remember, the output is a complete PHPer token. *
+* *
+* License: *
+* https://creativecommons.org/publicdomain/zero/1.0/ *
+*********************************************************/</span>
+<span class="hljs-keyword">const</span> <span class="hljs-variable constant_">N</span> = <span class="hljs-number">0</span> <span class="hljs-comment">/* Change it to your answer. */</span>;
+<span class="hljs-title function_ invoke__">assert</span>(<span class="hljs-number">0</span> &lt;= N &amp;&amp; N &lt;= <span class="hljs-number">0b11111_11111_11111_11111_11111</span>);
+
+<span class="hljs-variable">$token</span> = [
+<span class="hljs-number">0x14B499C</span>,
+<span class="hljs-number">0x0BE34CC</span>, <span class="hljs-number">0x01C9C69</span>,
+<span class="hljs-number">0x0ECA069</span>, <span class="hljs-number">0x01C2449</span>, <span class="hljs-number">0x0FDB166</span>, <span class="hljs-number">0x01C9C69</span>,
+<span class="hljs-number">0x01C1C66</span>, <span class="hljs-number">0x0FC1C47</span>, <span class="hljs-number">0x01C1C66</span>,
+<span class="hljs-number">0x10C5858</span>, <span class="hljs-number">0x1E4E3B8</span>, <span class="hljs-number">0x1A2F2F8</span>,
+];
+<span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$token</span> <span class="hljs-keyword">as</span> <span class="hljs-variable">$x</span>) {
+<span class="hljs-variable">$x</span> = <span class="hljs-variable">$x</span> ^ N;
+
+<span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">sprintf</span>(<span class="hljs-string">&#x27;%025b&#x27;</span>, <span class="hljs-variable">$x</span>);
+<span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">str_replace</span>(<span class="hljs-attr">search</span>: [<span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;1&#x27;</span>], <span class="hljs-attr">replace</span>: [<span class="hljs-string">&#x27; &#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>], <span class="hljs-attr">subject</span>: <span class="hljs-variable">$x</span>);
+<span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-string">&quot;\n&quot;</span>, <span class="hljs-title function_ invoke__">str_split</span>(<span class="hljs-variable">$x</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>));
+<span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;<span class="hljs-subst">{$x}</span>\n\n&quot;</span>;
+}</code></pre>
+
+ <p>
+ さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 トークンを得るためには、ソースコードを読み、定数 <code>N</code> を特定する必要がある。
+ </p>
+
+ <p>
+ ここでは、私の想定解を解説する。
+ </p>
+
+ <section id="section--q2-riddle--code-reading">
+ <h3><a href="#section--q2-riddle--code-reading">読解</a></h3>
+ <p>
+ まずはソースコードを読んでいく。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$token</span> = [
+<span class="hljs-comment">// 略</span>
+];</code></pre>
+
+ <p>
+ 数値からなる <code>$token</code> があり、各要素をループしている。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$x</span> = <span class="hljs-variable">$x</span> ^ N;</code></pre>
+
+ <p>
+ まずは排他的論理和 (xor) を取り、
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">sprintf</span>(<span class="hljs-string">&#x27;%025b&#x27;</span>, <span class="hljs-variable">$x</span>);</code></pre>
+
+ <p>
+ 二進数に変換して、
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">str_replace</span>(<span class="hljs-attr">search</span>: [<span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;1&#x27;</span>], <span class="hljs-attr">replace</span>: [<span class="hljs-string">&#x27; &#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>], <span class="hljs-attr">subject</span>: <span class="hljs-variable">$x</span>);</code></pre>
+
+ <p>
+ 0 を空白に、1 を <code>#</code> にし、
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-string">&quot;\n&quot;</span>, <span class="hljs-title function_ invoke__">str_split</span>(<span class="hljs-variable">$x</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>));</code></pre>
+
+ <p>
+ 5文字ごとに区切ったあと、改行で結合している。
+ </p>
+ </section>
+
+ <section id="section--q2-riddle--hint">
+ <h3><a href="#section--q2-riddle--hint">ヒント</a></h3>
+ <p>
+ 次に、ソースコードに書いてあるヒントを読んでいく。
+ </p>
+
+ <ul>
+ <li>
+ <code>N</code> それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている
+ </li>
+
+ <li>
+ <code>$token</code> の各要素は、1文字を表す
+ </li>
+
+ <li>
+ 1文字は 5x5 のセルからなる
+ </li>
+
+ <li>
+ 出力されるのは、完全な PHPer トークンである
+ </li>
+ </ul>
+
+ <p>
+ ここで、PHPer トークンは必ず <code>#</code> 記号から始まることを思いだすと、 <code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code>#</code> になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。
+ </p>
+ </section>
+
+ <section id="section--q2-riddle--solve">
+ <h3><a href="#section--q2-riddle--solve">解く</a></h3>
+ <p>
+ ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> に変換されるような <code>N</code> を見つければよい。
+ </p>
+
+ <p>
+ <code>N</code> は高々
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-title function_ invoke__">assert</span>(<span class="hljs-number">0</span> &lt;= N &amp;&amp; N &lt;= <span class="hljs-number">0b11111_11111_11111_11111_11111</span>);</code></pre>
+
+ <p>
+ なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+
+<span class="hljs-variable">$x</span> = <span class="hljs-number">0x14B499C</span>;
+
+<span class="hljs-variable">$x</span> = <span class="hljs-variable">$x</span> ^ N;
+
+<span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">sprintf</span>(<span class="hljs-string">&#x27;%025b&#x27;</span>, <span class="hljs-variable">$x</span>);
+<span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">str_replace</span>(<span class="hljs-attr">search</span>: [<span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;1&#x27;</span>], <span class="hljs-attr">replace</span>: [<span class="hljs-string">&#x27; &#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>], <span class="hljs-attr">subject</span>: <span class="hljs-variable">$x</span>);
+<span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-string">&quot;\n&quot;</span>, <span class="hljs-title function_ invoke__">str_split</span>(<span class="hljs-variable">$x</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>));
+
+<span class="hljs-title function_ invoke__">assert</span>(<span class="hljs-variable">$x</span> ===
+<span class="hljs-string">&quot; # # \n&quot;</span> .
+<span class="hljs-string">&quot;#####\n&quot;</span> .
+<span class="hljs-string">&quot; # # \n&quot;</span> .
+<span class="hljs-string">&quot;#####\n&quot;</span> .
+<span class="hljs-string">&quot; # # &quot;</span>);</code></pre>
+
+ <p>
+ この一連の変換に対する逆変換を考えると、次のようになる。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+
+<span class="hljs-variable">$x</span> =
+<span class="hljs-string">&quot; # # \n&quot;</span> .
+<span class="hljs-string">&quot;#####\n&quot;</span> .
+<span class="hljs-string">&quot; # # \n&quot;</span> .
+<span class="hljs-string">&quot;#####\n&quot;</span> .
+<span class="hljs-string">&quot; # # &quot;</span>;
+
+<span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-title function_ invoke__">explode</span>(<span class="hljs-string">&quot;\n&quot;</span>, <span class="hljs-variable">$x</span>));
+<span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">str_replace</span>(<span class="hljs-attr">search</span>: [<span class="hljs-string">&#x27; &#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>], <span class="hljs-attr">replace</span>: [<span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;1&#x27;</span>], <span class="hljs-attr">subject</span>: <span class="hljs-variable">$x</span>);
+<span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">bindec</span>(<span class="hljs-variable">$x</span>);
+
+<span class="hljs-variable">$n</span> = <span class="hljs-variable">$x</span> ^ <span class="hljs-number">0x14B499C</span>;
+
+<span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;N = <span class="hljs-subst">$n</span>\n&quot;</span>;</code></pre>
+
+ <p>
+ これを実行すると、<code>N</code> が得られる。
+ </p>
+ </section>
+ </section>
+
+ <section id="section--q3-toquine">
+ <h2><a href="#section--q3-toquine">第3問 toquine.php</a></h2>
+ <p>
+ ソースコードはこちら。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+
+<span class="hljs-comment">// License: https://creativecommons.org/publicdomain/zero/1.0/</span>
+<span class="hljs-comment">// This is a quine-like program to generate a PHPer token.</span>
+<span class="hljs-comment">// Execute it like this: php toquine.php | php | php | php | ...</span>
+
+<span class="hljs-variable">$s</span> = &lt;&lt;&lt;<span class="hljs-string">&#x27;Q&#x27;</span>
+<span class="hljs-meta">&lt;?</span>cuc
+<span class="hljs-comment">// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/</span>
+<span class="hljs-comment">// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra.</span>
+<span class="hljs-comment">// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ...</span>
+%f<span class="hljs-variable">$f</span> = %f;
+<span class="hljs-variable">$f</span> = <span class="hljs-title function_ invoke__">fge_ebg13</span>(<span class="hljs-variable">$f</span>); <span class="hljs-variable">$kf</span> = [
+%f,
+];
+<span class="hljs-variable">$g</span> = ahyy.snyfr; <span class="hljs-title function_ invoke__">sbe</span> (<span class="hljs-variable">$v</span> = <span class="hljs-number">0</span>; <span class="hljs-variable">$v</span> &lt;= <span class="hljs-title function_ invoke__">vagqvi</span>(__YVAR__-<span class="hljs-number">035</span>,<span class="hljs-number">6</span>); ++<span class="hljs-variable">$v</span>) <span class="hljs-title function_ invoke__">vs</span> (!<span class="hljs-title function_ invoke__">vffrg</span>(<span class="hljs-variable">$kf</span>[<span class="hljs-variable">$v</span>])) oernx; ryfr
+<span class="hljs-variable">$g</span> .= <span class="hljs-title function_ invoke__">vzcybqr</span>(<span class="hljs-string">&quot;\a&quot;</span>, <span class="hljs-title function_ invoke__">fge_fcyvg</span>(<span class="hljs-title function_ invoke__">fge_ercynpr</span>([<span class="hljs-string">&#x27;0&#x27;</span>,<span class="hljs-string">&#x27;1&#x27;</span>], [<span class="hljs-string">&#x27; &#x27;</span>,<span class="hljs-string">&#x27;##&#x27;</span>], <span class="hljs-title function_ invoke__">fcevags</span>(<span class="hljs-title function_ invoke__">pue</span>(<span class="hljs-number">37</span>) . <span class="hljs-string">&#x27;025o&#x27;</span>, <span class="hljs-variable">$kf</span>[<span class="hljs-variable">$v</span>])), <span class="hljs-number">012</span>)) . <span class="hljs-string">&quot;\a\a&quot;</span>;
+<span class="hljs-variable">$jf</span> = <span class="hljs-title function_ invoke__">neenl_znc</span>(<span class="hljs-title function_ invoke__">sa</span>(<span class="hljs-variable">$j</span>) =&gt; <span class="hljs-title function_ invoke__">vzcybqr</span>(<span class="hljs-string">&#x27;, &#x27;</span>, <span class="hljs-variable">$j</span>), <span class="hljs-title function_ invoke__">neenl_puhax</span>(<span class="hljs-title function_ invoke__">neenl_znc</span>(<span class="hljs-title function_ invoke__">sa</span>(<span class="hljs-variable">$k</span>) =&gt; <span class="hljs-title function_ invoke__">fcevags</span>(<span class="hljs-string">&#x27;0k&#x27;</span> . <span class="hljs-title function_ invoke__">pue</span>(<span class="hljs-number">37</span>) . <span class="hljs-string">&#x27;07K&#x27;</span>, <span class="hljs-variable">$k</span>), <span class="hljs-variable">$kf</span>), <span class="hljs-number">10</span>));
+<span class="hljs-title function_ invoke__">cevags</span>(<span class="hljs-variable">$f</span>, <span class="hljs-variable">$g</span>, <span class="hljs-title function_ invoke__">fge_ebg13</span>(<span class="hljs-string">&quot;&lt;&lt;&lt;&#x27;Q&#x27;\a<span class="hljs-subst">{$f}</span>\aQ&quot;</span>), <span class="hljs-title function_ invoke__">vzcybqr</span>(<span class="hljs-string">&quot;,\a&quot;</span>, <span class="hljs-variable">$jf</span>));
+Q;
+<span class="hljs-variable">$s</span> = <span class="hljs-title function_ invoke__">str_rot13</span>(<span class="hljs-variable">$s</span>); <span class="hljs-variable">$xs</span> = [
+<span class="hljs-number">0x0AFABEA</span>, <span class="hljs-number">0x1F294A7</span>, <span class="hljs-number">0x1F2109F</span>, <span class="hljs-number">0x1F294A7</span>, <span class="hljs-number">0x0002800</span>, <span class="hljs-number">0x1F2109F</span>, <span class="hljs-number">0x0117041</span>, <span class="hljs-number">0x1F294A7</span>, <span class="hljs-number">0x1FAD6B5</span>, <span class="hljs-number">0x1F295B7</span>,
+<span class="hljs-number">0x010FC21</span>, <span class="hljs-number">0x1FAD6B5</span>, <span class="hljs-number">0x1151151</span>, <span class="hljs-number">0x010FC21</span>, <span class="hljs-number">0x1F294A7</span>, <span class="hljs-number">0x1F295B7</span>, <span class="hljs-number">0x1FAD6B5</span>, <span class="hljs-number">0x1F294A7</span>, <span class="hljs-number">0x1F295B7</span>, <span class="hljs-number">0x1F8C63F</span>,
+<span class="hljs-number">0x1F8C631</span>, <span class="hljs-number">0x1FAD6B5</span>, <span class="hljs-number">0x17AD6BD</span>, <span class="hljs-number">0x17AD6BD</span>, <span class="hljs-number">0x1F8C63F</span>, <span class="hljs-number">0x1F295B7</span>,
+];
+<span class="hljs-variable">$t</span> = <span class="hljs-literal">null</span>.<span class="hljs-literal">false</span>; <span class="hljs-keyword">for</span> (<span class="hljs-variable">$i</span> = <span class="hljs-number">0</span>; <span class="hljs-variable">$i</span> &lt;= <span class="hljs-title function_ invoke__">intdiv</span>(<span class="hljs-keyword">__LINE__</span>-<span class="hljs-number">035</span>,<span class="hljs-number">6</span>); ++<span class="hljs-variable">$i</span>) <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$xs</span>[<span class="hljs-variable">$i</span>])) <span class="hljs-keyword">break</span>; <span class="hljs-keyword">else</span>
+<span class="hljs-variable">$t</span> .= <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-string">&quot;\n&quot;</span>, <span class="hljs-title function_ invoke__">str_split</span>(<span class="hljs-title function_ invoke__">str_replace</span>([<span class="hljs-string">&#x27;0&#x27;</span>,<span class="hljs-string">&#x27;1&#x27;</span>], [<span class="hljs-string">&#x27; &#x27;</span>,<span class="hljs-string">&#x27;##&#x27;</span>], <span class="hljs-title function_ invoke__">sprintf</span>(<span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-number">37</span>) . <span class="hljs-string">&#x27;025b&#x27;</span>, <span class="hljs-variable">$xs</span>[<span class="hljs-variable">$i</span>])), <span class="hljs-number">012</span>)) . <span class="hljs-string">&quot;\n\n&quot;</span>;
+<span class="hljs-variable">$ws</span> = <span class="hljs-title function_ invoke__">array_map</span>(fn(<span class="hljs-variable">$w</span>) =&gt; <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-string">&#x27;, &#x27;</span>, <span class="hljs-variable">$w</span>), <span class="hljs-title function_ invoke__">array_chunk</span>(<span class="hljs-title function_ invoke__">array_map</span>(fn(<span class="hljs-variable">$x</span>) =&gt; <span class="hljs-title function_ invoke__">sprintf</span>(<span class="hljs-string">&#x27;0x&#x27;</span> . <span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-number">37</span>) . <span class="hljs-string">&#x27;07X&#x27;</span>, <span class="hljs-variable">$x</span>), <span class="hljs-variable">$xs</span>), <span class="hljs-number">10</span>));
+<span class="hljs-title function_ invoke__">printf</span>(<span class="hljs-variable">$s</span>, <span class="hljs-variable">$t</span>, <span class="hljs-title function_ invoke__">str_rot13</span>(<span class="hljs-string">&quot;&lt;&lt;&lt;&#x27;D&#x27;\n<span class="hljs-subst">{$s}</span>\nD&quot;</span>), <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-string">&quot;,\n&quot;</span>, <span class="hljs-variable">$ws</span>));</code></pre>
+
+ <p>
+ コメントにもあるとおり、次のようにして実行すれば答えがでてくる。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ php toquine.php | php | php | php | ...</code></pre>
+
+ <p>
+ 実際にはもう少しパイプで繋げなければならない。
+ </p>
+
+ <section id="section--q3-toquine--commentary">
+ <h3><a href="#section--q3-toquine--commentary">解説</a></h3>
+ <section id="section--q3-toquine--commentary--quine">
+ <h4><a href="#section--q3-toquine--commentary--quine">プログラム全体</a></h4>
+ <p>
+ コメントにもあるとおり、これは quine (風) のプログラムになっている。 Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。
+ </p>
+
+ <p>
+ このプログラムは、実行すると自身とほとんど同じプログラムを出力する。 異なるのはトークンになっている部分のみである。
+ </p>
+ </section>
+
+ <section id="section--q3-toquine--commentary--tokens">
+ <h4><a href="#section--q3-toquine--commentary--tokens">トークン</a></h4>
+ <p>
+ <code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> とほぼ同じなので省略する。
+ </p>
+ </section>
+
+ <section id="section--q3-toquine--commentary--states">
+ <h4><a href="#section--q3-toquine--commentary--states">状態保持</a></h4>
+ <p>
+ トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。 このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code><em>LINE</em></code> から情報を取得している。
+ </p>
+ </section>
+
+ <section id="section--q3-toquine--commentary--rot-13">
+ <h4><a href="#section--q3-toquine--commentary--rot-13">ROT 13</a></h4>
+ <p>
+ Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。 これがあまり美しくないので、<code>toquine.php</code> では、ROT 13 変換を使って難読化した。
+ </p>
+
+ <p>
+ それにしてもなぜこんなものが標準ライブラリに……。
+ </p>
+ </section>
+ </section>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">おわりに</a></h2>
+ <p>
+ 解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。
+ </p>
+
+ <p>
+ 今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、 来年は 5問、より面白い問題を持っていきます。
+ </p>
+
+ <p>
+ 実はもう作りはじめているので、どうか来年もありますように……。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..595fb462
--- /dev/null
+++ b/vhosts/blog/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html
@@ -0,0 +1,166 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2022 nsfisis">
+ <meta name="description" content="ターミナルに任意の文字のバナーを表示するためのツールを Go で書いた。">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>term-banner: ターミナルにバナーを表示するツールを書いた | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">term-banner: ターミナルにバナーを表示するツールを書いた</h1>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2022-04-24">2022-04-24</time>: 公開
+ </li>
+ <li class="revision">
+ <time datetime="2022-04-27">2022-04-27</time>: -f オプションについて追記
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ こんなものを作った。
+ </p>
+
+ <pre class="highlight monospaced"><code>$ term-banner &apos;Hello, World!&apos; &apos;こんにちは、&apos; &apos;世界!&apos;</code></pre>
+
+ <p>
+ image::https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png[term-banner のスクリーンショット]
+ </p>
+
+ <p>
+ コマンドライン引数として渡した文字列をターミナルに大きく表示する。
+ </p>
+
+ <p>
+ リポジトリはこちら: <a href="https://github.com/nsfisis/term-banner">https://github.com/nsfisis/term-banner</a>
+ </p>
+ </section>
+
+ <section id="section--motivation">
+ <h2><a href="#section--motivation">Motivation</a></h2>
+ <p>
+ 以前、https://github.com/nsfisis/big-clock-mode[big-clock-mode] という似たようなプログラムを書いた。 これは tmux の <code>:clock-mode</code> コマンドに着想を得たもので、<code>:clock-mode</code> よりも大きく現在時刻を表示する。
+ </p>
+
+ <p>
+ <code>big-clock-mode</code> を開発したのは、次のようなシチュエーションで使うためである。 弊社では現在リモートワークが基本だが、web 会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。 こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。
+ </p>
+
+ <p>
+ それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。
+ </p>
+
+ <p>
+ しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。 どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。
+ </p>
+
+ <p>
+ そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。 まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。
+ </p>
+ </section>
+
+ <section id="section--program">
+ <h2><a href="#section--program">プログラム</a></h2>
+ <p>
+ 全体の流れは次のようになっている。
+ </p>
+
+ <ol numeration="arabic">
+ <li>
+ フォントファイルを読み込む
+ </li>
+
+ <li>
+ コマンドライン引数を Shift-JIS に変換する (フォントが Shift-JIS 基準で並んでいるため)
+ </li>
+
+ <li>
+ 1文字ずつレンダリングしていく
+ </li>
+ </ol>
+
+ <p>
+ <code>big-clock-mode</code> が Go 製なので、今回も Go で書いた。 PNG が標準ライブラリにあったり、Shift-JIS のエンコーディングが準標準ライブラリにあったりしたのは助かった。
+ </p>
+
+ <p>
+ フォントファイルは <code>go:embed</code> で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。 仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。
+ </p>
+ </section>
+
+ <section id="section--font">
+ <h2><a href="#section--font">フォント</a></h2>
+ <p>
+ フリーの 8x8 ビットマップフォントである、https://littlelimit.net/misaki.htm[美咲フォント 2021-05-05a 版] を使わせていただいた。
+ </p>
+
+ <p>
+ はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。 同じく 8x8 で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。
+ </p>
+
+ <p>
+ 美咲フォントは、平仮名・片仮名に留まらず、JIS 第一・第二水準の漢字までサポートしている。 第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。
+ </p>
+
+ <p>
+ さらに言うと、実のところ美咲フォントは実サイズ 7x7 で作られており、余白が設けられている。 これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。 おかげでコーディングまで楽になった。
+ </p>
+
+ <p>
+ ゴシック体と明朝体があったが、私の好みで明朝体の方にした。 ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。
+ </p>
+
+ <p>
+ 2022-04-27 追記: <code>-f</code> オプションで選べるようにした。
+ </p>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">おわりに</a></h2>
+ <p>
+ あなたもターミナルに住んでみませんか?
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..173b20d3
--- /dev/null
+++ b/vhosts/blog/public/posts/2022-05-01/phperkaigi-2022/index.html
@@ -0,0 +1,268 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2022 nsfisis">
+ <meta name="description" content="2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。">
+ <meta name="keywords" content="カンファレンス,PHP,PHPerKaigi">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHPerKaigi 2022 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHPerKaigi 2022</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/conference/">カンファレンス</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/phperkaigi/">PHPerKaigi</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2022-05-01">2022-05-01</time>: 公開
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ 2022-04-09 から 2022-04-11 にかけて開催された、<a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> に、 一般参加者として参加した。 弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a>はダイヤモンドスポンサーとなっており、 スポンサー枠のチケットを使わせていただいた。
+ </p>
+
+ <p>
+ 昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。
+ </p>
+ </section>
+
+ <section id="section--comments">
+ <h2><a href="#section--comments">感想</a></h2>
+ <section id="section--comments--great-sessions">
+ <h3><a href="#section--comments--great-sessions">厳選おすすめトーク</a></h3>
+ <p>
+ 多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。 是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。
+ </p>
+
+ <p>
+ <a href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし - 堅牢なコードを導く様々な設計のヒント</a>
+ </p>
+
+ <blockquote>
+ <p>
+ PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。
+ </p>
+
+ <p>
+ 本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。
+ </p>
+ </blockquote>
+
+ <p>
+ <a href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</a>
+ </p>
+
+ <blockquote>
+ <p>
+ PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice 理解していますか?
+ <br>
+ これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!
+ <br>
+ またそれらを理解した上でのエラーハンドリングを学びましょう。
+ </p>
+ </blockquote>
+
+ <p>
+ <a href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</a>
+ </p>
+
+ <blockquote>
+ <p>
+ 毎日流れてくるエラーに皆さんはどう向き合ってますか?
+ <br>
+ エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。
+ <br>
+ サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、
+ <br>
+ エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。
+ </p>
+ </blockquote>
+
+ <p>
+ <a href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</a>
+ </p>
+
+ <blockquote>
+ <p>
+ 昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。
+ </p>
+
+ <p>
+ 最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には
+ <br>
+ ・「(私の思う)良い設計」を実現するための意思決定
+ <br>
+ ・「ISUCONの問題」という位置付けに由来する取捨選択
+ <br>
+ ・移植中に遭遇したトラブルとその解決策
+ <br>
+ といった文脈や葛藤が存在しています。
+ </p>
+
+ <p>
+ 本発表はそれらを共有することで
+ <br>
+ ・PHPアプリケーションの設計、実装事例として役立ててもらう
+ <br>
+ ・ISUCONの言語移植に興味を持ってもらう
+ <br>
+ ・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう
+ <br>
+ ことを目的とします。
+ </p>
+ </blockquote>
+
+ <p>
+ <a href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</a>
+ </p>
+
+ <blockquote>
+ <p>
+ サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。
+ </p>
+
+ <p>
+ フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。
+ </p>
+
+ <p>
+ このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。
+ </p>
+ </blockquote>
+ </section>
+
+ <section id="section--comments--token-quizzes">
+ <h3><a href="#section--comments--token-quizzes">トークン問題の作成</a></h3>
+ <p>
+ 今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。 こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。
+ </p>
+ </section>
+
+ <section id="section--comments--phper-challenge">
+ <h3><a href="#section--comments--phper-challenge">PHPer チャレンジ</a></h3>
+ <p>
+ <a href="https://fortee.jp/phperkaigi-2022/challenge">1位</a>になった。
+ <br>
+ また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a> をいただいた。
+ </p>
+ </section>
+
+ <section id="section--comments--conference">
+ <h3><a href="#section--comments--conference">カンファレンス全体への感想</a></h3>
+ <p>
+ <a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> では、こんなことを書いた。
+ </p>
+
+ <blockquote>
+ <p>
+ 1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、 後から見返せる発表やスライドに注力してしまった、ということだ。 発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。
+ <br>
+ まあ初カンファレンスだし、とお茶を濁しておこう。
+ </p>
+ </blockquote>
+
+ <p>
+ この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。
+ <br>
+ これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、 質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。
+ </p>
+
+ <p>
+ なお、アンカンファレンスについては、1日目の終わりに<a href="https://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e">トークン問題の解説放送</a>もおこなった。
+ </p>
+
+ <p>
+ また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。 今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。
+ </p>
+ </section>
+ </section>
+
+ <section id="section--next-year">
+ <h2><a href="#section--next-year">そして来年へ……?</a></h2>
+ <p>
+ PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。
+ </p>
+
+ <ul>
+ <li>
+ プロポーザルを出す
+ </li>
+
+ <li>
+ PHPer チャレンジのトークン問題を 5題作成する
+ </li>
+
+ <li>
+ 現地に行く
+ </li>
+
+ <li>
+ PHPer チャレンジで圧勝する
+ </li>
+ </ul>
+
+ <p>
+ <hr>
+ </hr>
+ </p>
+
+ <p>
+ 最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。
+ </p>
+
+ <p>
+ ではまた来年。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..2d311e7f
--- /dev/null
+++ b/vhosts/blog/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html
@@ -0,0 +1,192 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2022 nsfisis">
+ <meta name="description" content="PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。">
+ <meta name="keywords" content="カンファレンス,PHP,PHP カンファレンス">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/conference/">カンファレンス</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/phpcon/">PHP カンファレンス</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2022-08-27">2022-08-27</time>: 公開
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ 本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a> が開催された (らしい)。
+ </p>
+
+ <p>
+ カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。
+ </p>
+
+ <ul>
+ <li>
+ ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</a>
+ </li>
+
+ <li>
+ スライド: <a href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</a>
+ </li>
+ </ul>
+ </section>
+
+ <section id="section--solution">
+ <h2><a href="#section--solution">解</a></h2>
+ <p>
+ 細かいレギュレーションは不明だったので、勝手に定めた。
+ </p>
+
+ <ul>
+ <li>
+ コマンドライン引数の第1引数で受けとる
+ </li>
+
+ <li>
+ 結果は標準出力に出す
+ </li>
+
+ <li>
+ コンマの直後にはスペースを1つ置く
+ </li>
+
+ <li>
+ 末尾コンマは禁止
+ </li>
+
+ <li>
+ 数字でないものは入ってこないものとする
+ </li>
+
+ <li>
+ 負数は入ってこないものとする
+ </li>
+ </ul>
+
+ <p>
+ 書いたものがこちら:
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">[<span class="hljs-meta">&lt;?php</span> <span class="hljs-variable">$n</span>=<span class="hljs-variable">$argv</span>[<span class="hljs-number">1</span>];<span class="hljs-keyword">foreach</span>([<span class="hljs-number">1e4</span>,<span class="hljs-number">5e3</span>,<span class="hljs-number">2e3</span>,<span class="hljs-number">1e3</span>,<span class="hljs-number">500</span>,<span class="hljs-number">100</span>,<span class="hljs-number">50</span>,<span class="hljs-number">10</span>,<span class="hljs-number">5</span>,<span class="hljs-number">1</span>]<span class="hljs-keyword">as</span><span class="hljs-variable">$x</span>)<span class="hljs-keyword">for</span>(;<span class="hljs-variable">$n</span>&gt;=<span class="hljs-variable">$x</span>;<span class="hljs-variable">$n</span>-=<span class="hljs-variable">$x</span>)<span class="hljs-variable">$r</span>[]=<span class="hljs-variable">$x</span>;<span class="hljs-keyword">echo</span> <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-string">&#x27;, &#x27;</span>,<span class="hljs-variable">$r</span>??[]);<span class="hljs-meta">?&gt;</span>]</code></pre>
+
+ <p>
+ しめて 123 バイトとなった (末尾改行を含めずにカウント)。
+ </p>
+
+ <p>
+ こちらは改行とスペースを追加したバージョン:
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">[<span class="hljs-meta">&lt;?php</span>
+
+<span class="hljs-variable">$n</span> = <span class="hljs-variable">$argv</span>[<span class="hljs-number">1</span>];
+<span class="hljs-keyword">foreach</span> ([<span class="hljs-number">1e4</span>, <span class="hljs-number">5e3</span>, <span class="hljs-number">2e3</span>, <span class="hljs-number">1e3</span>, <span class="hljs-number">500</span>, <span class="hljs-number">100</span>, <span class="hljs-number">50</span>, <span class="hljs-number">10</span>, <span class="hljs-number">5</span>, <span class="hljs-number">1</span>] <span class="hljs-keyword">as</span> <span class="hljs-variable">$x</span>)
+ <span class="hljs-keyword">for</span> (; <span class="hljs-variable">$n</span> &gt;= <span class="hljs-variable">$x</span>; <span class="hljs-variable">$n</span> -= <span class="hljs-variable">$x</span>)
+ <span class="hljs-variable">$r</span>[] = <span class="hljs-variable">$x</span>;
+<span class="hljs-keyword">echo</span> <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-string">&#x27;, &#x27;</span>, <span class="hljs-variable">$r</span> ?? []);
+
+<span class="hljs-meta">?&gt;</span>]</code></pre>
+ </section>
+
+ <section id="section--techniques">
+ <h2><a href="#section--techniques">使用したテクニック</a></h2>
+ <section id="section--techniques--exponential-notation">
+ <h3><a href="#section--techniques--exponential-notation">指数表記</a></h3>
+ <p>
+ 割と多くの言語のゴルフで使えるテクニック。 <code>e</code> を用いた指数表記で、大きな数を短く表す。 このコードでは <code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。
+ </p>
+ </section>
+
+ <section id="section--techniques--shorten-loop">
+ <h3><a href="#section--techniques--shorten-loop">foreach や for の中身を1つの文に</a></h3>
+ <p>
+ <code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、 通常 <code>{</code> を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code> を省略できる。 C言語などでも使える。
+ </p>
+ </section>
+
+ <section id="section--techniques--omit-initialization">
+ <h3><a href="#section--techniques--omit-initialization">$r に初期値を入れない</a></h3>
+ <p>
+ PHP では、<code>$r[] = ......</code> のような配列の末尾に追加する式を実行したとき、 <code>$r</code> が未定義だった場合は <code>$r</code> を勝手に定義して空の配列で初期化してくれる。 これを利用すると、<code>$r = [];</code> のような初期化が不要になる。
+ </p>
+
+ <p>
+ ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code> が未定義になってしまい、 <code>implode()</code> に渡すところでエラーになる。 それを防ぐために <code>$r ?? []</code> を使っている。
+ </p>
+
+ <p>
+ もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。
+ </p>
+ </section>
+
+ <section id="section--techniques--put-text-outside-php-tag">
+ <h3><a href="#section--techniques--put-text-outside-php-tag">PHP タグの外に文字列を置く</a></h3>
+ <p>
+ PHP では、<code>&lt;?php</code> <code>?&gt;</code> で囲われた部分の外側にある文字列は、そのまま出力される。 今回のケースでは、先頭と末尾に必ず <code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。
+ </p>
+ </section>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">おわりに</a></h2>
+ <p>
+ 最後になりましたが、<a href="https://twitter.com/m3m0r7">めもりー</a>さん、楽しい問題をありがとうございました。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..ae8cea42
--- /dev/null
+++ b/vhosts/blog/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2022 nsfisis">
+ <meta name="description" content="先日、私の勤めるデジタルサーカス株式会社が、PHP Foundation へ寄付をおこないました。
+ 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>弊社の PHP Foundation への寄付に寄せて | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">弊社の PHP Foundation への寄付に寄せて</h1>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2022-08-31">2022-08-31</time>: 公開
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ <em role="strong">注: これは私個人の意見であり、所属する組織を代表するものではありません。</em>
+ </p>
+
+ <p>
+ 先日、私の勤める <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> が <a href="https://opencollective.com/phpfoundation">PHP Foundation</a> へ $2,000 の寄付をおこないました。
+ </p>
+
+ <p>
+ 記事: <a href="https://www.dgcircus.com/news/581">https://www.dgcircus.com/news/581</a>
+ </p>
+
+ <p>
+ 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。
+ </p>
+ </section>
+
+ <section id="section--why">
+ <h2><a href="#section--why">なぜ?</a></h2>
+ <p>
+ 組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。
+ </p>
+
+ <p>
+ 当時の考えを端的にまとめた社内チャットの投稿があったので、それを引用します:
+ </p>
+
+ <blockquote>
+ <p>
+ 結局これを通したい (私の中での) 最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、 ↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、 寄付の報告が流れてきたり、OSS のフリーライドの話が流れてきたりするたびに、自尊心が毀損される、というか (これは大袈裟すぎる表現で、実際にはそこまで明確に傷ついているわけではありませんが)。
+ </p>
+
+ <p>
+ 追記: 「肩身が狭くなる」というのがより適切でした。
+ </p>
+ </blockquote>
+
+ <p>
+ ※文中の「↑にしても」は、ここに載せていない別の投稿を指しています。
+ </p>
+
+ <p>
+ OSS を金銭的に支援したり、技術カンファレンスへ協賛したり (あるいは <a href="https://twitter.com/tomzoh">CTO</a> がカンファレンスを年2で主催したり: <a href="https://iosdc.jp">iOSDC</a> <a href="https://phperkaigi.jp">PHPerKaigi</a>) といった行為は、コミュニティへの貢献であると同時に、社員に対する精神的福利厚生でもあると言えるでしょう (知らんけど)。 これらは、技術や技術者を大切にする組織である、ということの、対外的にも対内的にも強力なメッセージなのです。
+ </p>
+
+ <p>
+ 以上が、私が社内で寄付の件を進めた (かなり私的な) 理由です。
+ </p>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">おわりに</a></h2>
+ <p>
+ 最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。 この場を借りて感謝申し上げます。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..f29cf154
--- /dev/null
+++ b/vhosts/blog/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html
@@ -0,0 +1,739 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2022 nsfisis">
+ <meta name="description" content="PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。">
+ <meta name="keywords" content="PHP">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【PHP】 fizzbuzz を書く。1行あたり2文字で。 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【PHP】 fizzbuzz を書く。1行あたり2文字で。</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2022-09-28">2022-09-28</time>: 公開
+ </li>
+ <li class="revision">
+ <time datetime="2022-09-29">2022-09-29</time>: 小さな文言の修正・変更
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">記事の構成について</a></h2>
+ <p>
+ この記事は、普通の fizzbuzz を徐々に変形して最終形にしていく、という構成で書かれている。 最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、 <a href="https://gist.github.com/nsfisis/04c227d5a419867472a0b23a83ad2919#file-fizzbuzz-php-2-letters-per-line-and-supports-php-8-x-without-warnings">このページ</a> にソースコードがあるので、そちらを先に見てほしい。
+ </p>
+ </section>
+
+ <section id="section--regulations">
+ <h2><a href="#section--regulations">レギュレーション</a></h2>
+ <p>
+ PHP で、次のような制約の下に fizzbuzz を書いた。
+ </p>
+
+ <ul>
+ <li>
+ 1行あたりの文字数は2文字までに収めること (ただし <code>&lt;?php</code> タグは除く)
+ <ul>
+ <li>
+ 厳密な定義: <code>&lt;?php</code> タグ以降のソースコードが、2 byte ごとにラインフィード (LF) で区切られること
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ スペースやタブを使用しないこと
+ </li>
+
+ <li>
+ ループのアンロールをしないこと
+ <ul>
+ <li>
+ 100 回ループの代わりに 100 回コードをコピペ、というのは禁止
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ PHP 7.4〜8.1 で動作すること
+ </li>
+
+ <li>
+ 実行時に Notice や Warning が出ないこと
+ </li>
+
+ <li>
+ 標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)
+ </li>
+ </ul>
+
+ <p>
+ 備考: PHP には <code>short_open_tag</code> というオプションがあり、 これを有効にするとファイル冒頭の <code>&lt;?php</code> の代わりに <code>&lt;?</code> を使うことができ、文字どおり1行2文字で書ける。 ただ、このオプションはデフォルト off になっている環境が多いようなので、今回は使わないことにした。
+ </p>
+ </section>
+
+ <section id="section--problems">
+ <h2><a href="#section--problems">主な障害</a></h2>
+ <p>
+ 1行あたりの文字数など、適当に改行を挟めばいいだけではないのか?
+ </p>
+
+ <p>
+ 特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。
+ </p>
+
+ <pre class="highlight" language="c" linenumbering="unnumbered"><code class="highlight">#\
+i\
+n\
+c\
+l\
+u\
+d\
+e\
+&lt;\
+s\
+t\
+d\
+i\
+o\
+.\
+h\
+&gt;\
+<span class="hljs-comment">/*
+*/</span>
+i\
+n\
+t\
+<span class="hljs-comment">/*
+*/</span>
+m\
+a\
+i\
+n(
+){
+f\
+o\
+r(
+i\
+n\
+t\
+<span class="hljs-comment">/*
+*/</span>
+i=
+<span class="hljs-number">1</span>;
+i&lt;
+<span class="hljs-number">1</span>\
+<span class="hljs-number">0</span>\
+<span class="hljs-number">0</span>;
+i\
++\
++)
+<span class="hljs-keyword">if</span>
+(i
+%\
+<span class="hljs-number">15</span>
+==
+<span class="hljs-number">0</span>)
+p\
+r\
+i\
+n\
+t\
+f(
+<span class="hljs-string">&quot;\
+F\
+i\
+z\
+z\
+B\
+u\
+z\
+z\
+%\
+c\
+&quot;</span>,
+<span class="hljs-number">10</span>
+);
+
+<span class="hljs-comment">/* あとは同じように普通のプログラムを変形するだけなので省略 */</span></code></pre>
+
+ <p>
+ バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。
+ </p>
+
+ <p>
+ さて、PHP ではそもそもバックスラッシュを行継続に使うことができない。 これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。 例えば、<code>echo</code> で出力することや、<code>for</code> でループすること、 <code>new</code> でインスタンスを生成することができない。 特に、出力は fizzbuzz をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。
+ </p>
+
+ <p>
+ 当然、名前が3文字以上ある関数も使えない。なお、標準 PHP の範囲内において、名前が 2文字以下の関数は以下のとおりである:
+ </p>
+
+ <ul>
+ <li>
+ <code>_</code>: <code>gettext</code> のエイリアス
+ </li>
+
+ <li>
+ <code>dl</code>: 拡張モジュールをロードする
+ </li>
+
+ <li>
+ <code>pi</code>: 円周率を返す
+ </li>
+ </ul>
+
+ <p>
+ (環境によって多少は変わるかも)
+ </p>
+
+ <p>
+ 2文字の関数を定義しまくった拡張モジュールを用意しておいて <code>dl()</code> で読み込む行為は、レギュレーションで定めた
+ </p>
+
+ <blockquote>
+ <ul>
+ <li>
+ 標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)
+ </li>
+ </ul>
+ </blockquote>
+
+ <p>
+ に反する (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。
+ </p>
+
+ <p>
+ また、2文字だと文字列がまともに書けないのも辛い。<code>&apos;&apos;</code> だけで2文字使うので、 「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$a</span>
+=<span class="hljs-string">&#x27;
+a&#x27;</span>
+;;</code></pre>
+
+ <p>
+ とすると <code>$a</code> は <code>&quot;\na&quot;</code> になるのだが、余計な改行が入ってしまう。
+ </p>
+
+ <p>
+ これらの障害をどのように乗り越えるのか、次節から見ていく。
+ </p>
+ </section>
+
+ <section id="section--commentary">
+ <h2><a href="#section--commentary">解説</a></h2>
+ <section id="section--commentary--normal-fizzbuzz">
+ <h3><a href="#section--commentary--normal-fizzbuzz">普通の (?) fizzbuzz</a></h3>
+ <p>
+ まずは普通に書くとしよう。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+
+<span class="hljs-keyword">for</span> (<span class="hljs-variable">$i</span> = <span class="hljs-number">1</span>; <span class="hljs-variable">$i</span> &lt; <span class="hljs-number">100</span>; <span class="hljs-variable">$i</span>++) {
+ <span class="hljs-keyword">echo</span> ((<span class="hljs-variable">$i</span> % <span class="hljs-number">3</span> ? <span class="hljs-string">&#x27;&#x27;</span> : <span class="hljs-string">&#x27;Fizz&#x27;</span>) . (<span class="hljs-variable">$i</span> % <span class="hljs-number">5</span> ? <span class="hljs-string">&#x27;&#x27;</span> : <span class="hljs-string">&#x27;Buzz&#x27;</span>) ?: <span class="hljs-variable">$i</span>) . <span class="hljs-string">&quot;\n&quot;</span>;
+}</code></pre>
+
+ <p>
+ 素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。
+ </p>
+ </section>
+
+ <section id="section--commentary--remove-keywords">
+ <h3><a href="#section--commentary--remove-keywords"><code>for</code> の排除</a></h3>
+ <p>
+ <code>for</code> は、3文字もある長いキーワードである。 こんなものは使えない。<code>array_</code> 系の関数を使って、適当に置き換えるとしよう。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+
+<span class="hljs-variable">$s</span> = <span class="hljs-title function_ invoke__">range</span>(<span class="hljs-number">1</span>, <span class="hljs-number">100</span>);
+<span class="hljs-title function_ invoke__">array_walk</span>(
+<span class="hljs-variable">$s</span>,
+fn(<span class="hljs-variable">$i</span>) =&gt;
+<span class="hljs-title function_ invoke__">printf</span>(((<span class="hljs-variable">$i</span> % <span class="hljs-number">3</span> ? <span class="hljs-string">&#x27;&#x27;</span> : <span class="hljs-string">&#x27;Fizz&#x27;</span>) . (<span class="hljs-variable">$i</span> % <span class="hljs-number">5</span> ? <span class="hljs-string">&#x27;&#x27;</span> : <span class="hljs-string">&#x27;Buzz&#x27;</span>) ?: <span class="hljs-variable">$i</span>) . <span class="hljs-string">&quot;\n&quot;</span>),
+);</code></pre>
+
+ <p>
+ <code>array_walk</code> や <code>range</code>、<code>printf</code> といった <code>for</code> よりも長いトークンが現れてしまったが、これは次節で直すことにする。 なお、<code>echo</code> は文 (statement) であり式 (expression) ではないので、式である <code>printf</code> に置き換えた。
+ </p>
+ </section>
+
+ <section id="section--commentary--shorten-function-invocation">
+ <h3><a href="#section--commentary--shorten-function-invocation">関数呼び出しの短縮</a></h3>
+ <p>
+ <code>range</code>、<code>array_walk</code>、<code>printf</code> は長すぎるのでどうにかせねばならない。 ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+
+<span class="hljs-variable">$r</span> = <span class="hljs-string">&#x27;range&#x27;</span>;
+<span class="hljs-variable">$w</span> = <span class="hljs-string">&#x27;array_walk&#x27;</span>;
+<span class="hljs-variable">$p</span> = <span class="hljs-string">&#x27;printf&#x27;</span>;
+
+<span class="hljs-variable">$s</span> = <span class="hljs-variable">$r</span>(<span class="hljs-number">1</span>, <span class="hljs-number">100</span>);
+<span class="hljs-variable">$w</span>(
+<span class="hljs-variable">$s</span>,
+<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$i</span></span>) =&gt;</span>
+<span class="hljs-variable">$p</span>(((<span class="hljs-variable">$i</span> % <span class="hljs-number">3</span> ? <span class="hljs-string">&#x27;&#x27;</span> : <span class="hljs-string">&#x27;Fizz&#x27;</span>) . (<span class="hljs-variable">$i</span> % <span class="hljs-number">5</span> ? <span class="hljs-string">&#x27;&#x27;</span> : <span class="hljs-string">&#x27;Buzz&#x27;</span>) ?: <span class="hljs-variable">$i</span>) . <span class="hljs-string">&quot;\n&quot;</span>),
+);</code></pre>
+
+ <p>
+ これで関数を呼び出している所は短くなった。 では、<code>$r</code> や <code>$w</code> や <code>$p</code>、 また <code>&apos;Fizz&apos;</code> や <code>&apos;Buzz&apos;</code> はどうやって 1 行 2 文字に収めるのか。 次のテクニックへ移ろう。
+ </p>
+ </section>
+
+ <section id="section--commentary--incompatible-solution">
+ <h3><a href="#section--commentary--incompatible-solution">余談: PHP 8.x で動作しなくてもいいなら</a></h3>
+ <p>
+ 今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。
+ </p>
+
+ <blockquote>
+ <ul>
+ <li>
+ PHP 7.4〜8.1 で動作すること
+ </li>
+ </ul>
+ </blockquote>
+
+ <p>
+ というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。 例えば、 <code>Fizz</code> という文字列が欲しければ、次のようにする。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$f</span>
+=F
+.i
+.z
+.z
+;;</code></pre>
+
+ <p>
+ こうして簡単に文字列を作れる。 なお、この仕様は 7.x 時点でも警告を受けるので、<code>@</code> 演算子を使って抑制してやるとよい。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$f</span>
+=@
+F.
+@i
+.<span class="hljs-comment">#</span>
+@z
+.<span class="hljs-comment">#</span>
+@z
+;;</code></pre>
+
+ <p>
+ むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。
+ </p>
+ </section>
+
+ <section id="section--commentary--shorten-string-literals">
+ <h3><a href="#section--commentary--shorten-string-literals">文字列リテラルの短縮</a></h3>
+ <p>
+ 実際に使った手法の説明に移る。
+ </p>
+
+ <p>
+ ずばり、文字列同士のビット演算を使う。 PHP では、文字列同士でビット演算 (<code>&amp;</code>、<code>|</code>、<code>^</code>) をした場合、 文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$a</span> = <span class="hljs-string">&quot;12345&quot;</span>;
+<span class="hljs-variable">$b</span> = <span class="hljs-string">&quot;world&quot;</span>;
+
+<span class="hljs-comment">// $a ^ $b は次のコードと同じ</span>
+<span class="hljs-variable">$result</span> = <span class="hljs-string">&#x27;&#x27;</span>;
+<span class="hljs-keyword">for</span> (<span class="hljs-variable">$i</span> = <span class="hljs-number">0</span>; <span class="hljs-variable">$i</span> &lt; <span class="hljs-title function_ invoke__">min</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$a</span>), <span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$b</span>)); <span class="hljs-variable">$i</span>++) {
+<span class="hljs-variable">$result</span> .= <span class="hljs-variable">$a</span>[<span class="hljs-variable">$i</span>] ^ <span class="hljs-variable">$b</span>[<span class="hljs-variable">$i</span>];
+}
+
+<span class="hljs-keyword">echo</span> <span class="hljs-variable">$result</span>;
+<span class="hljs-comment">// =&gt; F]AXQ</span></code></pre>
+
+ <p>
+ これを踏まえ、次のコードを見てみよう。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$x</span> = <span class="hljs-string">&quot;x\nOm\n&quot;</span>;
+<span class="hljs-variable">$y</span> = <span class="hljs-string">&quot;\nk!\no&quot;</span>;
+<span class="hljs-variable">$r</span> = <span class="hljs-variable">$x</span> ^ <span class="hljs-variable">$y</span>;
+<span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;<span class="hljs-subst">$r</span>\n&quot;</span>;</code></pre>
+
+ <p>
+ 実行すると、<code>range</code> が表示される。 さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。 書きかえてみよう。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$x</span>
+=<span class="hljs-string">&#x27;x
+Om
+&#x27;</span>;
+<span class="hljs-variable">$y</span>
+=<span class="hljs-string">&#x27;
+k!
+o&#x27;</span>
+;
+
+<span class="hljs-variable">$r</span> = <span class="hljs-variable">$x</span> ^ <span class="hljs-variable">$y</span>;
+<span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;<span class="hljs-subst">$r</span>\n&quot;</span>;</code></pre>
+
+ <p>
+ さらに <code>#</code> を使って適当に調整すると、次のようになる。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$x</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-string">&#x27;x
+Om
+&#x27;</span>;
+<span class="hljs-variable">$y</span>
+=<span class="hljs-string">&#x27;
+k!
+o&#x27;</span>
+;<span class="hljs-comment">#</span>
+<span class="hljs-variable">$r</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-variable">$x</span>
+^<span class="hljs-comment">#</span>
+<span class="hljs-variable">$y</span>
+;<span class="hljs-comment">#</span>
+
+<span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;<span class="hljs-subst">$r</span>\n&quot;</span>;</code></pre>
+
+ <p>
+ 1行あたり2文字で、<code>range</code> という文字列を生成することに成功した。 他の必要な文字列にも、同様の処理をほどこす。
+ </p>
+
+ <p>
+ 備考: <code>Buzz</code> 中にある小文字の <code>u</code> は、このロジックだと non-printable な文字になってしまう。 ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。
+ </p>
+ </section>
+ </section>
+
+ <section id="section--stretched-fizzbuzz">
+ <h2><a href="#section--stretched-fizzbuzz">完成系</a></h2>
+ <p>
+ 完成したものがこちら。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+
+<span class="hljs-variable">$x</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-string">&#x27;i
+S&#x27;</span>
+;;
+<span class="hljs-variable">$y</span>
+=<span class="hljs-string">&#x27;
+b!
+&#x27;</span>;
+<span class="hljs-variable">$c</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-variable">$x</span>
+^<span class="hljs-comment">#</span>
+<span class="hljs-variable">$y</span>
+;<span class="hljs-comment">#</span>
+<span class="hljs-variable">$x</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-string">&#x27;x
+Om
+&#x27;</span>;
+<span class="hljs-variable">$y</span>
+=<span class="hljs-string">&#x27;
+k!
+o&#x27;</span>
+;<span class="hljs-comment">#</span>
+<span class="hljs-variable">$r</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-variable">$x</span>
+^<span class="hljs-comment">#</span>
+<span class="hljs-variable">$y</span>
+;<span class="hljs-comment">#</span>
+<span class="hljs-variable">$x</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-string">&#x27;k
+Sk
+~}
+Ma
+&#x27;</span>;
+<span class="hljs-variable">$y</span>
+=<span class="hljs-string">&#x27;
+x!
+s!
+k!
+&#x27;</span>;
+<span class="hljs-variable">$w</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-variable">$x</span>
+^<span class="hljs-comment">#</span>
+<span class="hljs-variable">$y</span>
+;<span class="hljs-comment">#</span>
+<span class="hljs-variable">$x</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-string">&#x27;z
+Hd
+G&#x27;</span>
+;<span class="hljs-comment">#</span>
+<span class="hljs-variable">$y</span>
+=<span class="hljs-string">&#x27;
+x!
+~!
+&#x27;</span>;
+<span class="hljs-variable">$p</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-variable">$x</span>
+^<span class="hljs-comment">#</span>
+<span class="hljs-variable">$y</span>
+;<span class="hljs-comment">#</span>
+<span class="hljs-variable">$x</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-string">&#x27;L
+[p
+&#x27;</span>;
+<span class="hljs-variable">$y</span>
+=<span class="hljs-string">&#x27;
+c!
+&#x27;</span>;
+<span class="hljs-variable">$f</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-variable">$x</span>
+^<span class="hljs-comment">#</span>
+<span class="hljs-variable">$y</span>
+;<span class="hljs-comment">#</span>
+<span class="hljs-variable">$x</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-string">&#x27;H
+[p
+&#x27;</span>;
+<span class="hljs-variable">$y</span>
+=<span class="hljs-string">&#x27;
+_!
+&#x27;</span>;
+<span class="hljs-variable">$b</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-variable">$x</span>
+^<span class="hljs-comment">#</span>
+<span class="hljs-variable">$y</span>
+;<span class="hljs-comment">#</span>
+<span class="hljs-variable">$b</span>
+[<span class="hljs-number">1</span>
+]=
+<span class="hljs-variable">$c</span>
+(<span class="hljs-comment">#</span>
+<span class="hljs-number">13</span>
+*<span class="hljs-number">9</span>
+);
+<span class="hljs-variable">$s</span>
+=<span class="hljs-comment">#</span>
+<span class="hljs-variable">$r</span>
+(<span class="hljs-number">1</span>
+,(
+<span class="hljs-number">10</span>
+**
+<span class="hljs-number">2</span>)
+);
+<span class="hljs-variable">$w</span>
+(<span class="hljs-comment">#</span>
+<span class="hljs-variable">$s</span>
+,<span class="hljs-comment">#</span>
+<span class="hljs-function"><span class="hljs-keyword">fn</span>
+(<span class="hljs-params">#
+<span class="hljs-variable">$i</span>
+</span>)#
+=&gt;</span>
+<span class="hljs-variable">$p</span>
+((
+(<span class="hljs-comment">#</span>
+<span class="hljs-variable">$i</span>
+%<span class="hljs-number">3</span>
+?<span class="hljs-comment">#</span>
+<span class="hljs-string">&#x27;&#x27;</span>
+:<span class="hljs-comment">#</span>
+<span class="hljs-variable">$f</span>
+).
+(<span class="hljs-comment">#</span>
+<span class="hljs-variable">$i</span>
+%<span class="hljs-number">5</span>
+?<span class="hljs-comment">#</span>
+<span class="hljs-string">&#x27;&#x27;</span>
+:<span class="hljs-comment">#</span>
+<span class="hljs-variable">$b</span>
+)?
+:<span class="hljs-comment">#</span>
+<span class="hljs-variable">$i</span>
+)<span class="hljs-comment">#</span>
+.<span class="hljs-string">&#x27;
+&#x27;</span>)
+);</code></pre>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">感想など</a></h2>
+ <p>
+ PHP は、スクリプト言語の中だとシンタックスシュガーが少ない (体感)。 この挑戦は不可能に思われたが、PHP マニュアルとにらめっこしていたらなんとかなった。
+ </p>
+
+ <p>
+ みんなもプログラムを細長くしよう。
+ </p>
+ </section>
+
+ <section id="section--alternative-solution">
+ <h2><a href="#section--alternative-solution">余談2: 別解</a></h2>
+ <p>
+ PHP では、バッククォートを使ってシェルを呼び出せる。 これは <code>shell_exec</code> 関数と等価である。 さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+
+<span class="hljs-title function_ invoke__">printf</span>(`
+e\
+c\
+h\
+o\
+\
+<span class="hljs-number">1</span>\
+<span class="hljs-number">2</span>\
+<span class="hljs-number">3</span>\
+`);</code></pre>
+
+ <p>
+ なお、ここでは簡単のため出力に <code>printf</code> をそのまま使っているが、 実際には <code>printf</code> という文字列を合成して可変関数で呼び出す。
+ </p>
+
+ <p>
+ ただし、これでは
+ </p>
+
+ <blockquote>
+ <ul>
+ <li>
+ スペースやタブを使用しないこと
+ </li>
+ </ul>
+ </blockquote>
+
+ <p>
+ に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。
+ </p>
+
+ <p>
+ もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+
+<span class="hljs-variable">$c</span> = <span class="hljs-string">&#x27;chr&#x27;</span>;
+
+${
+<span class="hljs-string">&#x27;_
+&#x27;</span>}
+=<span class="hljs-comment">#</span>
+<span class="hljs-variable">$c</span>
+(<span class="hljs-comment">#</span>
+<span class="hljs-number">32</span>
+).
+<span class="hljs-variable">$c</span>
+(<span class="hljs-comment">#</span>
+<span class="hljs-number">92</span>
+);
+
+<span class="hljs-title function_ invoke__">printf</span>(`
+e\
+c\
+h\
+o\
+${
+<span class="hljs-string">&#x27;_
+&#x27;</span>}
+<span class="hljs-number">1</span>\
+<span class="hljs-number">2</span>\
+<span class="hljs-number">3</span>\
+`);</code></pre>
+
+ <p>
+ 先程と同じく、<code>chr</code> や <code>printf</code> を生成する部分は長くなるので省いた。
+ </p>
+
+ <pre class="highlight monospaced"><code>${
+&apos;_
+&apos;}</code></pre>
+
+ <p>
+ は変数で、中にはスペースとエスケープが入っている (<code>chr(32) . chr(92)</code>)。 シェルに渡されている文字列は次のようになる。
+ </p>
+
+ <pre class="highlight monospaced"><code>e\
+c\
+h\
+o\
+\
+1\
+2\
+3\</code></pre>
+
+ <p>
+ これは、前掲したコマンドと同じだ。 かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。 Fizzbuzz のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう (試してないけど)。
+ </p>
+
+ <p>
+ ということでこれは別解ということにしておく。
+ </p>
+
+ <p>
+ ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。
+ </p>
+
+ <pre class="highlight monospaced"><code>${
+&apos;_
+&apos;}</code></pre>
+
+ <p>
+ 最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..eaa210c5
--- /dev/null
+++ b/vhosts/blog/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html
@@ -0,0 +1,212 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2022 nsfisis">
+ <meta name="description" content="来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、ボツになった問題を公開する (その 1)。">
+ <meta name="keywords" content="PHP,PHPerKaigi">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHPerKaigi 2023: ボツになったトークン問題 その 1 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHPerKaigi 2023: ボツになったトークン問題 その 1</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/phperkaigi/">PHPerKaigi</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2022-10-23">2022-10-23</time>: 公開
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ 2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の、 <a href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</a> において、 昨年と同様に、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> から、 トークン問題を出題予定である。
+ </p>
+
+ <p>
+ 昨年のトークン問題の記事はこちら: <a href="/posts/2022-04-09/phperkaigi-2022-tokens">PHPerKaigi 2022 トークン問題の解説</a>
+ </p>
+
+ <p>
+ すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。 せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。
+ </p>
+
+ <p>
+ 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。
+ </p>
+ </section>
+
+ <section id="section--quiz">
+ <h2><a href="#section--quiz">問題</a></h2>
+ <p>
+ 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+
+$π = <span class="hljs-variable">$argv</span>[<span class="hljs-number">1</span>] ?? <span class="hljs-literal">null</span>;
+<span class="hljs-keyword">if</span> ($π === <span class="hljs-literal">null</span>) {
+ <span class="hljs-keyword">exit</span>(<span class="hljs-string">&#x27;No input.&#x27;</span>);
+}
+$π = <span class="hljs-title function_ invoke__">trim</span>($π);
+<span class="hljs-keyword">if</span> (!<span class="hljs-title function_ invoke__">is_numeric</span>($π)) {
+ <span class="hljs-keyword">exit</span>(<span class="hljs-string">&#x27;Invalid input.&#x27;</span>);
+}
+
+<span class="hljs-variable">$s</span> = <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-title function_ invoke__">array_map</span>(<span class="hljs-title function_ invoke__">chr</span>(...), <span class="hljs-title function_ invoke__">str_split</span>($π, <span class="hljs-number">2</span>)));
+
+<span class="hljs-title function_ invoke__">preg_match</span>(<span class="hljs-string">&#x27;/(\x23.+?) /&#x27;</span>, <span class="hljs-variable">$s</span>, <span class="hljs-variable">$m</span>);
+<span class="hljs-variable">$t</span> = <span class="hljs-variable">$m</span>[<span class="hljs-number">1</span>] ?? <span class="hljs-string">&#x27;&#x27;</span>;
+
+<span class="hljs-keyword">if</span> (<span class="hljs-title function_ invoke__">md5</span>(<span class="hljs-variable">$t</span>) === <span class="hljs-string">&#x27;056e831a4146bf123e8ea16613303d2e&#x27;</span>) {
+ <span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;Token: <span class="hljs-subst">{$t}</span>\n&quot;</span>;
+} <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;Failed.\n&quot;</span>;
+}</code></pre>
+ </section>
+
+ <section id="section--how-to-obtain-token">
+ <h2><a href="#section--how-to-obtain-token">トークン入手方法</a></h2>
+ <p>
+ ソースを見るとわかるとおり、<code>$argv[1]</code> を参照している。 それを <code>$π</code> なる変数に代入しているので、円周率を渡してみる。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ php Q.php 3.14
+Failed.</code></pre>
+
+ <p>
+ 失敗してしまった。精度を上げてみる。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ php Q.php 3.1415
+Failed.</code></pre>
+
+ <p>
+ だめだった。これを成功するまで繰り返す。
+ </p>
+
+ <p>
+ 最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ php Q.php 3.1415926535897932
+Token: #YO</code></pre>
+
+ <p>
+ めでたくトークン「<code>#YO</code>」が手に入った。
+ </p>
+ </section>
+
+ <section id="section--commentary">
+ <h2><a href="#section--commentary">解説</a></h2>
+ <p>
+ 短いので頭から追っていく。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">$π = <span class="hljs-variable">$argv</span>[<span class="hljs-number">1</span>] ?? <span class="hljs-literal">null</span>;
+<span class="hljs-keyword">if</span> ($π === <span class="hljs-literal">null</span>) {
+ <span class="hljs-keyword">exit</span>(<span class="hljs-string">&#x27;No input.&#x27;</span>);
+}
+$π = <span class="hljs-title function_ invoke__">trim</span>($π);
+<span class="hljs-keyword">if</span> (!<span class="hljs-title function_ invoke__">is_numeric</span>($π)) {
+ <span class="hljs-keyword">exit</span>(<span class="hljs-string">&#x27;Invalid input.&#x27;</span>);
+}</code></pre>
+
+ <p>
+ 入力のバリデーション部分。数値のみ受け付ける。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$s</span> = <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-title function_ invoke__">array_map</span>(<span class="hljs-title function_ invoke__">chr</span>(...), <span class="hljs-title function_ invoke__">str_split</span>($π, <span class="hljs-number">2</span>)));</code></pre>
+
+ <p>
+ <code>$π</code> を 2 文字ごとに区切り (<code>str_split</code>)、 数値を ASCII コードと見做して文字に変換 (<code>chr</code>) して結合 (<code>implode</code>) している。
+ </p>
+
+ <p>
+ 例えば、<code>$π</code> が <code>&apos;656667&apos;</code> だったとすると、 <code>65</code>、<code>66</code>、<code>67</code> に対応した <code>&apos;A&apos;</code>、<code>&apos;B&apos;</code>、<code>&apos;C&apos;</code> へと変換され、<code>&apos;ABC&apos;</code> になる。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">$π = <span class="hljs-string">&#x27;656667&#x27;</span>;
+<span class="hljs-variable">$s</span> = <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-title function_ invoke__">array_map</span>(<span class="hljs-title function_ invoke__">chr</span>(...), <span class="hljs-title function_ invoke__">str_split</span>($π, <span class="hljs-number">2</span>)));
+<span class="hljs-keyword">echo</span> <span class="hljs-variable">$s</span>;
+<span class="hljs-comment">// =&gt; ABC</span></code></pre>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-title function_ invoke__">preg_match</span>(<span class="hljs-string">&#x27;/(\x23.+?) /&#x27;</span>, <span class="hljs-variable">$s</span>, <span class="hljs-variable">$m</span>);
+<span class="hljs-variable">$t</span> = <span class="hljs-variable">$m</span>[<span class="hljs-number">1</span>] ?? <span class="hljs-string">&#x27;&#x27;</span>;</code></pre>
+
+ <p>
+ 正規表現でマッチングしている。<code>\x23</code> は <code>#</code> と同じであることに留意すると、 この正規表現は「<code>#</code> から始まる 2 以上の長さ (含 <code>#</code>) の文字列で、 最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。
+ </p>
+
+ <p>
+ なお、<code>#</code> を直接書いていないのは、<code>/#.+?) /</code> と書くと、 <code>#.+?)</code> という意図せぬトークンが登録されてしまうからである。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">if</span> (<span class="hljs-title function_ invoke__">md5</span>(<span class="hljs-variable">$t</span>) === <span class="hljs-string">&#x27;056e831a4146bf123e8ea16613303d2e&#x27;</span>) {
+ <span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;Token: <span class="hljs-subst">{$t}</span>\n&quot;</span>;
+} <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;Failed.\n&quot;</span>;
+}</code></pre>
+
+ <p>
+ 最後にトークンのハッシュ値を見て、想定解かどうかを確認する。
+ </p>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">おわりに</a></h2>
+ <p>
+ 円周率を何桁も計算して ASCII コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。
+ </p>
+
+ <p>
+ 最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた (ちなみに、それでも <code>M_PI</code> や <code>pi()</code> では精度が足りない)。 見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。 むしろ、100 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..20297c1b
--- /dev/null
+++ b/vhosts/blog/public/posts/2022-10-28/setup-server-for-this-site/index.html
@@ -0,0 +1,316 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2022 nsfisis">
+ <meta name="description" content="GitHub Pages でホストしていたこのサイトを VPS へ移行したので、そのときにやったことのメモ。99 % 自分用。">
+ <meta name="keywords" content="備忘録">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【備忘録】 このサイト用の VPS をセットアップしたときのメモ | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【備忘録】 このサイト用の VPS をセットアップしたときのメモ</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/note-to-self/">備忘録</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2022-10-28">2022-10-28</time>: 公開
+ </li>
+ <li class="revision">
+ <time datetime="2023-08-30">2023-08-30</time>: ssh_config に IdentitiesOnly yes を追加
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS に移行した。 そのときにおこなったサーバのセットアップ作業を書き残しておく。 99 % 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。
+ </p>
+
+ <p>
+ 未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。
+ </p>
+ </section>
+
+ <section id="section--vps">
+ <h2><a href="#section--vps">VPS</a></h2>
+ <p>
+ <a href="https://vps.sakura.ad.jp/">さくらの VPS</a> の 2 GB プラン。 そこまで真面目に選定していないので、困ったら移動するかも。
+ </p>
+ </section>
+
+ <section id="section--preparation">
+ <h2><a href="#section--preparation">事前準備</a></h2>
+ <section id="section--preparation--hostname">
+ <h3><a href="#section--preparation--hostname">サーバのホスト名を決める</a></h3>
+ <p>
+ モチベーションが上がるという効能がある。今回は藤原定家から取って <code>teika</code> にした。 たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。
+ </p>
+ </section>
+
+ <section id="section--preparation--ssh-key">
+ <h3><a href="#section--preparation--ssh-key">SSH の鍵生成</a></h3>
+ <p>
+ ローカルマシンで鍵を生成する。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/teika.key
+$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key</code></pre>
+
+ <p>
+ <code>teika.key</code> はローカルからサーバへの接続用、<code>github2teika.key</code> は、 GitHub Actions からサーバへのデプロイ用。
+ </p>
+ </section>
+
+ <section id="section--preparation--ssh-config">
+ <h3><a href="#section--preparation--ssh-config">SSH の設定</a></h3>
+ <p>
+ <code>.ssh/config</code> に設定しておく。
+ </p>
+
+ <pre class="highlight" language="ssh_config" linenumbering="unnumbered"><code>Host teika
+ HostName **********
+ User **********
+ Port **********
+ IdentityFile ~/.ssh/teika.key
+ IdentitiesOnly yes</code></pre>
+ </section>
+ </section>
+
+ <section id="section--basic-setup">
+ <h2><a href="#section--basic-setup">基本のセットアップ</a></h2>
+ <section id="section--basic-setup--login">
+ <h3><a href="#section--basic-setup--login">SSH 接続</a></h3>
+ <p>
+ VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。
+ </p>
+ </section>
+
+ <section id="section--basic-setup--user">
+ <h3><a href="#section--basic-setup--user">ユーザを作成する</a></h3>
+ <p>
+ 管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。 <code>sudo</code> グループに追加して <code>sudo</code> できるようにし、<code>su</code> で切り替え。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo adduser **********
+$ sudo adduser ********** sudo
+$ su **********
+$ cd</code></pre>
+ </section>
+
+ <section id="section--basic-setup--hostname">
+ <h3><a href="#section--basic-setup--hostname">ホスト名を変える</a></h3>
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo hostname teika</code></pre>
+ </section>
+
+ <section id="section--basic-setup--public-key">
+ <h3><a href="#section--basic-setup--public-key">公開鍵を置く</a></h3>
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ mkdir ~/.ssh
+$ chmod 700 ~/.ssh
+$ vi ~/.ssh/authorized_keys</code></pre>
+
+ <p>
+ <code>authorized_keys</code> には、ローカルで生成した <code>~/.ssh/teika.key.pub</code> と <code>~/.ssh/github2teika.key.pub</code> の内容をコピーする。
+ </p>
+ </section>
+
+ <section id="section--basic-setup--ssh-config">
+ <h3><a href="#section--basic-setup--ssh-config">SSH の設定</a></h3>
+ <p>
+ SSH の設定を変更し、少しでも安全にしておく。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
+$ sudo vi /etc/ssh/sshd_config</code></pre>
+
+ <ul>
+ <li>
+ <code>Port</code> を変更
+ </li>
+
+ <li>
+ <code>PermitRootLogin</code> を <code>no</code> に
+ </li>
+
+ <li>
+ <code>PasswordAuthentication</code> を <code>no</code> に
+ </li>
+ </ul>
+
+ <p>
+ そして設定を反映。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo systemctl restart sshd
+$ sudo systemctl status sshd</code></pre>
+ </section>
+
+ <section id="section--basic-setup--ssh-connect">
+ <h3><a href="#section--basic-setup--ssh-connect">SSH で接続確認</a></h3>
+ <p>
+ 今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。 セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ ssh teika</code></pre>
+ </section>
+
+ <section id="section--basic-setup--close-ports">
+ <h3><a href="#section--basic-setup--close-ports">ポートの遮断</a></h3>
+ <p>
+ デフォルトの 22 番を閉じ、設定したポートだけ空ける。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo ufw deny ssh
+$ sudo ufw allow *******
+$ sudo ufw enable
+$ sudo ufw reload
+$ sudo ufw status</code></pre>
+
+ <p>
+ ここでもう一度 SSH の接続確認を挟む。
+ </p>
+ </section>
+
+ <section id="section--basic-setup--ssh-key-for-github">
+ <h3><a href="#section--basic-setup--ssh-key-for-github">GitHub 用の SSH 鍵</a></h3>
+ <p>
+ GitHub に置いてある private リポジトリをサーバから clone したいので、SSH 鍵を生成して置いておく。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github.key
+$ cat ~/.ssh/github.key.pub</code></pre>
+
+ <p>
+ <a href="https://github.com/settings/ssh">GitHub の設定画面</a> から、この公開鍵を追加する。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ vi ~/.ssh/config</code></pre>
+
+ <p>
+ 設定はこう。
+ </p>
+
+ <pre class="highlight" language="ssh_config" linenumbering="unnumbered"><code>Host github.com
+ HostName github.com
+ User git
+ Port 22
+ IdentityFile ~/.ssh/github.key
+ IdentitiesOnly yes</code></pre>
+
+ <p>
+ 最後に接続できるか確認しておく。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ ssh -T github.com</code></pre>
+ </section>
+
+ <section id="section--basic-setup--upgrade-packages">
+ <h3><a href="#section--basic-setup--upgrade-packages">パッケージの更新</a></h3>
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo apt update
+$ sudo apt upgrade
+$ sudo apt update
+$ sudo apt upgrade
+$ sudo apt autoremove</code></pre>
+ </section>
+ </section>
+
+ <section id="section--site-hosting-setup">
+ <h2><a href="#section--site-hosting-setup">サイトホスティング用のセットアップ</a></h2>
+ <section id="section--site-hosting-setup--dns">
+ <h3><a href="#section--site-hosting-setup--dns">DNS に IP アドレスを登録する</a></h3>
+ <p>
+ このサーバは固定の IP アドレスがあるので、<code>A</code> レコードに直接入れるだけで済んだ。
+ </p>
+ </section>
+
+ <section id="section--site-hosting-setup--install-softwares">
+ <h3><a href="#section--site-hosting-setup--install-softwares">使うソフトウェアのインストール</a></h3>
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo apt install docker docker-compose git make</code></pre>
+ </section>
+
+ <section id="section--site-hosting-setup--docker">
+ <h3><a href="#section--site-hosting-setup--docker">メインユーザが Docker を使えるように</a></h3>
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo adduser ********** docker</code></pre>
+ </section>
+
+ <section id="section--site-hosting-setup--open-http-ports">
+ <h3><a href="#section--site-hosting-setup--open-http-ports">HTTP/HTTPS を通す</a></h3>
+ <p>
+ 80 番と 443 番を空ける。
+ </p>
+
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo ufw allow 80/tcp
+$ sudo ufw allow 443/tcp
+$ sudo ufw reload
+$ sudo ufw status</code></pre>
+ </section>
+
+ <section id="section--site-hosting-setup--clone-repositories">
+ <h3><a href="#section--site-hosting-setup--clone-repositories">リポジトリのクローン</a></h3>
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ cd
+$ git clone git@github.com:nsfisis/nsfisis.dev.git
+$ cd nsfisis.dev
+$ git submodule update --init</code></pre>
+ </section>
+
+ <section id="section--site-hosting-setup--certbot">
+ <h3><a href="#section--site-hosting-setup--certbot">certbot で証明書取得</a></h3>
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ docker-compose up -d acme-challenge
+$ make setup</code></pre>
+ </section>
+
+ <section id="section--site-hosting-setup--run-server">
+ <h3><a href="#section--site-hosting-setup--run-server">サーバを稼動させる</a></h3>
+ <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ make serve</code></pre>
+ </section>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">感想</a></h2>
+ <p>
+ (業務でなく) 個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。 とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。 コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。 次の式年遷宮では、手順の一部だけでも自動化したいところ。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..a870f0d4
--- /dev/null
+++ b/vhosts/blog/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html
@@ -0,0 +1,225 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2022 nsfisis">
+ <meta name="description" content="来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、ボツになった問題を公開する (その 2)。">
+ <meta name="keywords" content="PHP,PHPerKaigi">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHPerKaigi 2023: ボツになったトークン問題 その 2 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHPerKaigi 2023: ボツになったトークン問題 その 2</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/phperkaigi/">PHPerKaigi</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2022-11-19">2022-11-19</time>: 公開
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ 2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の <a href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</a> において、 昨年と同様に、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> からトークン問題を出題予定である。
+ </p>
+
+ <p>
+ 昨年のトークン問題の記事はこちら: <a href="/posts/2022-04-09/phperkaigi-2022-tokens/">PHPerKaigi 2022 トークン問題の解説</a>
+ </p>
+
+ <p>
+ すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。
+ </p>
+
+ <p>
+ 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。
+ </p>
+
+ <p>
+ その 1 はこちら: <a href="/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/">PHPerKaigi 2023: ボツになったトークン問題 その 1</a>
+ </p>
+ </section>
+
+ <section id="section--quiz">
+ <h2><a href="#section--quiz">問題</a></h2>
+ <p>
+ 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span></code></pre>
+
+ <p>
+ &quot;And Then There Were None&quot; (そして誰もいなくなった) と名付けた作品。変則 quine (自分自身と同じソースコードを出力するプログラム) になっている。
+ </p>
+ </section>
+
+ <section id="section--how-to-obtain-token">
+ <h2><a href="#section--how-to-obtain-token">トークン入手方法</a></h2>
+ <p>
+ 実行してみると、次のような出力が得られる。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment">#</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span></code></pre>
+
+ <p>
+ 1 行目を除き、先ほどのコードとほぼ同じものが出てきた。もう一度実行してみる。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment">#</span>
+W
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span>
+<span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;​&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;​&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span></code></pre>
+
+ <p>
+ 今度は 2 行目が書き換えられた。すべての行が変化するまで繰り返すと次のようになる。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment">#</span>
+W
+E
+L
+O
+V
+E
+P
+H
+P</code></pre>
+
+ <p>
+ トークン「#WELOVEPHP」が手に入った。
+ </p>
+ </section>
+
+ <section id="section--commentary">
+ <h2><a href="#section--commentary">解説</a></h2>
+ <p>
+ 一見すると同じ行が 10 行並んでいるだけなのにも関わらず、なぜそれぞれの行で出力が変わるのか。ソースコードをコピーして、適当なエディタに貼り付けるとわかりやすい。
+ </p>
+
+ <p>
+ Vim で開くと次のようになる (1 行目を抜粋)。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span> <span class="hljs-title function_ invoke__">printf</span>((<span class="hljs-keyword">isset</span>(<span class="hljs-variable">$s</span>)?<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">&quot;&lt;200b&gt;&quot;</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>))(<span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;&lt;200b&gt;&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;&lt;200b&gt;&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span>).<span class="hljs-string">&quot;\n&quot;</span>,<span class="hljs-string">&quot;\x27<span class="hljs-subst">$s</span>\x27&quot;</span>);<span class="hljs-meta">?&gt;</span></code></pre>
+
+ <p>
+ <code>&lt;200b&gt;</code> と表示されているのは、Unicode の U+200b で、ゼロ幅スペースである。
+ </p>
+
+ <div class="admonition">
+ <div class="admonition-label">
+ NOTE
+ </div>
+ <div class="admonition-content">
+ <p>
+ エディタによっては、ゼロ幅スペースが見えないことがある。VSCode ではブラウザと同様に不可視だった。
+ </p>
+ </div>
+ </div>
+
+ <p>
+ 文字列リテラルの中にゼロ幅スペースを仕込むことで、見た目を変えずに情報をエンコードすることが可能となる。
+ </p>
+
+ <p>
+ 続いて、トークンへの変換ロジックを解析する。注目すべきはこの部分だ。以下、ゼロ幅スペースは Vim での表示に合わせて <code>&lt;200b&gt;</code> と記載する。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=&gt;</span><span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$s</span>)/<span class="hljs-number">3</span>)</code></pre>
+
+ <p>
+ PHP の <code>strlen()</code> は文字列のバイト数を返す。1 行目の <code>$s</code> は以下の内容となっており、
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$s</span>=<span class="hljs-string">&#x27;&lt;200b&gt;&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,&quot;&lt;200b&gt;&quot;):fn($s)=&gt;chr(strlen($s)/3))($s=%s).&quot;\n&quot;,&quot;\x27$s\x27&quot;);?&gt;&#x27;</span></code></pre>
+
+ <p>
+ このソースコードは UTF-8 で書かれているので、105 バイトになる。それを 3 で割ると 35 となり、これは <code>#</code> の ASCII コードと一致する。他の行も、同様にしてゼロ幅スペースを詰めることで文字列長を調整し、トークンをエンコードしている。
+ </p>
+
+ <p>
+ デコード部以外の部分は、quine のための記述である。
+ </p>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">おわりに</a></h2>
+ <p>
+ <a href="https://blog.rust-lang.org/2021/11/01/cve-2021-42574.html">CVE-2021-42574</a> に着想を得た作品。この脆弱性は、Unicode の制御文字である left-to-right mark と right-to-left mark を利用し、ソースコードの実際の内容を欺く、というもの。簡単のためゼロ幅スペースを用いることとし、ついでに quine にもするとこうなった。
+ </p>
+
+ <p>
+ ボツになった理由は、ゼロ幅スペースを表示してくるエディタが想像以上に多かったため。「同じ行が並んでいるだけなのに出力が異なる」というアイデアの根幹を崩されてしまうので、この問題は不採用となった。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..397f6ceb
--- /dev/null
+++ b/vhosts/blog/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html
@@ -0,0 +1,410 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2023 nsfisis">
+ <meta name="description" content="来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、ボツになった問題を公開する (その 3)。">
+ <meta name="keywords" content="PHP,PHPerKaigi">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHPerKaigi 2023: ボツになったトークン問題 その 3 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHPerKaigi 2023: ボツになったトークン問題 その 3</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/phperkaigi/">PHPerKaigi</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2023-01-10">2023-01-10</time>: 公開
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ 2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の <a href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</a> において、 昨年と同様に、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> からトークン問題を出題予定である。
+ </p>
+
+ <p>
+ 昨年のトークン問題の記事はこちら: <a href="/posts/2022-04-09/phperkaigi-2022-tokens/">PHPerKaigi 2022 トークン問題の解説</a>
+ </p>
+
+ <p>
+ すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。 せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。
+ </p>
+
+ <p>
+ 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ → 忘れていたので 12 月公開予定だった記事を今書いている)。
+ </p>
+
+ <ul>
+ <li>
+ その 1 はこちら: <a href="/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/">PHPerKaigi 2023: ボツになったトークン問題 その 1</a>
+ </li>
+
+ <li>
+ その 2 はこちら: <a href="/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/">PHPerKaigi 2023: ボツになったトークン問題 その 2</a>
+ </li>
+ </ul>
+ </section>
+
+ <section id="section--quiz">
+ <h2><a href="#section--quiz">問題</a></h2>
+ <p>
+ 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+<span class="hljs-keyword">try</span> {
+ <span class="hljs-title function_ invoke__">f</span>(<span class="hljs-title function_ invoke__">g</span>() / <span class="hljs-keyword">__LINE__</span>);
+} <span class="hljs-keyword">catch</span> (<span class="hljs-built_in">Throwable</span> <span class="hljs-variable">$e</span>) {
+ <span class="hljs-keyword">while</span> (<span class="hljs-variable">$e</span> = <span class="hljs-variable">$e</span>-&gt;<span class="hljs-title function_ invoke__">getPrevious</span>()) <span class="hljs-title function_ invoke__">printf</span>(<span class="hljs-string">&#x27;%c&#x27;</span>, <span class="hljs-variable">$e</span>-&gt;<span class="hljs-title function_ invoke__">getLine</span>() + <span class="hljs-number">23</span>);
+ <span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;\n&quot;</span>;
+}
+<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">f</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> <span class="hljs-variable">$i</span></span>) </span>{
+ <span class="hljs-keyword">if</span> (<span class="hljs-variable">$i</span> &lt; <span class="hljs-number">0</span>) <span class="hljs-title function_ invoke__">f</span>();
+ <span class="hljs-keyword">try</span> {
+ <span class="hljs-keyword">match</span> (<span class="hljs-variable">$i</span>) {
+ <span class="hljs-number">0</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+
+
+ <span class="hljs-number">15</span>, <span class="hljs-number">36</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+ <span class="hljs-number">14</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+ <span class="hljs-number">37</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+
+
+
+
+
+
+
+
+
+ <span class="hljs-number">6</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+ <span class="hljs-number">5</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+ <span class="hljs-number">22</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+
+
+
+ <span class="hljs-number">34</span>, <span class="hljs-number">35</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+
+
+
+
+
+
+
+ <span class="hljs-number">25</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+ <span class="hljs-number">17</span>, <span class="hljs-number">21</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+ <span class="hljs-number">24</span>, <span class="hljs-number">32</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+
+
+
+
+
+
+ <span class="hljs-number">33</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+ <span class="hljs-number">16</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+
+ <span class="hljs-number">18</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+
+
+
+
+
+
+
+ <span class="hljs-number">7</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+ <span class="hljs-number">2</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+ <span class="hljs-number">1</span>, <span class="hljs-number">20</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+ <span class="hljs-number">10</span>, <span class="hljs-number">28</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+ <span class="hljs-number">8</span>, <span class="hljs-number">12</span>, <span class="hljs-number">26</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+ <span class="hljs-number">4</span>, <span class="hljs-number">9</span>, <span class="hljs-number">13</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+
+
+
+
+ <span class="hljs-number">31</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+ <span class="hljs-number">29</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+ <span class="hljs-number">11</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+
+
+ <span class="hljs-number">3</span>, <span class="hljs-number">19</span>, <span class="hljs-number">23</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+
+ <span class="hljs-number">27</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+ <span class="hljs-number">30</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+ };
+ } <span class="hljs-keyword">finally</span> {
+ <span class="hljs-title function_ invoke__">f</span>(<span class="hljs-variable">$i</span> - <span class="hljs-number">1</span>);
+ }
+}
+
+
+
+
+
+
+
+<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">g</span>(<span class="hljs-params"></span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">__LINE__</span>;
+}</code></pre>
+
+ <p>
+ &quot;Catchline&quot; と名付けた作品。実行するとトークン <code>#base64_decode(&apos;SGVsbG8sIFdvcmxkIQ==&apos;)</code> が得られる。
+ </p>
+
+ <p>
+ トークンは PHP の式になっていて、評価すると <code>Hello, World!</code> という文字列になる。PHPer チャレンジのトークンには空白を含められないという制約があるが、こういった形でトークンにすれば回避できる。
+ </p>
+ </section>
+
+ <section id="section--commentary">
+ <h2><a href="#section--commentary">解説</a></h2>
+ <section id="section--commentary--summary">
+ <h3><a href="#section--commentary--summary">概要</a></h3>
+ <p>
+ 例外が発生した行数にデータをエンコードし、それを <code>catch</code> で捕まえて表示している。
+ </p>
+ </section>
+
+ <section id="section--commentary--chain-of-exceptions">
+ <h3><a href="#section--commentary--chain-of-exceptions">例外オブジェクトの連鎖</a></h3>
+ <p>
+ <a href="https://www.php.net/class.Exception"><code>Exception</code></a> や <a href="https://www.php.net/class.Error"><code>Error</code></a> には <code>$previous</code> というプロパティがあり、コンストラクタの第3引数から渡すことができる。主に 2つの用法がある:
+ </p>
+
+ <ul>
+ <li>
+ エラーを処理している途中に起こった別のエラーに、元のエラー情報を含める
+ </li>
+
+ <li>
+ 内部エラーをラップして作られたエラーに、内部エラーの情報を含める
+ </li>
+ </ul>
+
+ <p>
+ このうち 1つ目のケースは、 <code>finally</code> 節の中でエラーを投げると PHP 処理系が勝手に <code>$previous</code> を設定してくれる。
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+
+<span class="hljs-keyword">try</span> {
+ <span class="hljs-keyword">try</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Exception</span>(<span class="hljs-string">&quot;Error 1&quot;</span>);
+ } <span class="hljs-keyword">finally</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Exception</span>(<span class="hljs-string">&quot;Error 2&quot;</span>);
+ }
+} <span class="hljs-keyword">catch</span> (<span class="hljs-built_in">Exception</span> <span class="hljs-variable">$e</span>) {
+ <span class="hljs-keyword">echo</span> <span class="hljs-variable">$e</span>-&gt;<span class="hljs-title function_ invoke__">getMessage</span>() . PHP_EOL;
+ <span class="hljs-comment">// =&gt; Error 2</span>
+ <span class="hljs-keyword">echo</span> <span class="hljs-variable">$e</span>-&gt;<span class="hljs-title function_ invoke__">getPrevious</span>()-&gt;<span class="hljs-title function_ invoke__">getMessage</span>() . PHP_EOL;
+ <span class="hljs-comment">// =&gt; Error 1</span>
+}</code></pre>
+
+ <p>
+ この知識を元に、トークンの出力部を解析してみる。
+ </p>
+ </section>
+
+ <section id="section--commentary--output">
+ <h3><a href="#section--commentary--output">出力部の解析</a></h3>
+ <p>
+ 出力部をコメントや改行を追加して再掲する:
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+<span class="hljs-keyword">try</span> {
+ <span class="hljs-title function_ invoke__">f</span>(<span class="hljs-title function_ invoke__">g</span>() / <span class="hljs-keyword">__LINE__</span>);
+} <span class="hljs-keyword">catch</span> (<span class="hljs-built_in">Throwable</span> <span class="hljs-variable">$e</span>) {
+ <span class="hljs-keyword">while</span> (<span class="hljs-variable">$e</span> = <span class="hljs-variable">$e</span>-&gt;<span class="hljs-title function_ invoke__">getPrevious</span>()) {
+ <span class="hljs-title function_ invoke__">printf</span>(<span class="hljs-string">&#x27;%c&#x27;</span>, <span class="hljs-variable">$e</span>-&gt;<span class="hljs-title function_ invoke__">getLine</span>() + <span class="hljs-number">23</span>);
+ }
+ <span class="hljs-keyword">echo</span> <span class="hljs-string">&quot;\n&quot;</span>;
+}</code></pre>
+
+ <p>
+ 出力をおこなう <code>catch</code> 節を見てみると、 <code>Throwable::getPrevious()</code> を呼び出してエラーチェインを辿り、 <code>Throwable::getLine()</code> でエラーが発生した行数を取得している。その行数に <code>23</code> なるマジックナンバーを足し、フォーマット指定子 <code>%c</code> で出力している。
+ </p>
+
+ <p>
+ フォーマット指定子 <code>%c</code> は、整数を ASCII コード<span></span> と見做して印字する。トークン <code>#base64_decode(&apos;SGVsbG8sIFdvcmxkIQ==&apos;)</code> の <code>b</code> であれば、ASCII コード <code>98</code> なので、75 行目で発生したエラー、
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-number">1</span>, <span class="hljs-number">20</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,</code></pre>
+
+ <p>
+ によって表現されている。エラーを起こす方法はいろいろと考えられるが、今回はゼロ除算を使った。
+ </p>
+
+ <p>
+ それでは、エラーチェインを作る箇所、関数 <code>f()</code> を見ていく。
+ </p>
+ </section>
+
+ <section id="section--commentary--data-construction">
+ <h3><a href="#section--commentary--data-construction">データ構成部の解析</a></h3>
+ <p>
+ <code>f()</code> の定義を再掲する (エラーオブジェクトの行数を利用しているので、一部分だけ抜き出すと値が変わることに注意):
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">f</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> <span class="hljs-variable">$i</span></span>) </span>{
+ <span class="hljs-keyword">if</span> (<span class="hljs-variable">$i</span> &lt; <span class="hljs-number">0</span>) <span class="hljs-title function_ invoke__">f</span>();
+ <span class="hljs-keyword">try</span> {
+ <span class="hljs-keyword">match</span> (<span class="hljs-variable">$i</span>) {
+ <span class="hljs-number">0</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>, <span class="hljs-comment">// 12 行目</span>
+
+
+
+ <span class="hljs-number">15</span>, <span class="hljs-number">36</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+ <span class="hljs-number">14</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+ <span class="hljs-number">37</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>,
+
+ <span class="hljs-comment">// (略)</span>
+
+ <span class="hljs-number">30</span> =&gt; <span class="hljs-number">0</span> / <span class="hljs-number">0</span>, <span class="hljs-comment">// 97 行目</span>
+ };
+ } <span class="hljs-keyword">finally</span> {
+ <span class="hljs-title function_ invoke__">f</span>(<span class="hljs-variable">$i</span> - <span class="hljs-number">1</span>);
+ }
+}</code></pre>
+
+ <p>
+ 前述のように、 <code>finally</code> 節でエラーを投げると PHP 処理系が <code>$previous</code> を設定する。ここでは、エラーを繋げるために <code>f()</code> を再帰呼び出ししている。最初に <code>f()</code> を呼び出している箇所を確認すると、
+ </p>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
+<span class="hljs-keyword">try</span> {
+ <span class="hljs-title function_ invoke__">f</span>(<span class="hljs-title function_ invoke__">g</span>() / <span class="hljs-keyword">__LINE__</span>); <span class="hljs-comment">// 3 行目</span></code></pre>
+
+ <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">g</span>(<span class="hljs-params"></span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">__LINE__</span>; <span class="hljs-comment">// 111 行目</span>
+}</code></pre>
+
+ <p>
+ <code>f()</code> には <code>111 / 3</code> で <code>37</code> が渡されることがわかる。そこから 1 ずつ減らして再帰呼び出ししていき、0 より小さくなったら <code>f()</code> を引数なしで呼び出す。引数の数が足りないと呼び出しに失敗するので、再帰はここで止まる。
+ </p>
+
+ <p>
+ エラーチェインは、最後に発生したエラーを先頭とした単方向連結リストになっているので、順に
+ </p>
+
+ <ol numeration="arabic">
+ <li>
+ <code>f()</code> の引数が足りないことによる呼び出し失敗
+ </li>
+
+ <li>
+ <code>f(0)</code> の呼び出しで発生したゼロ除算
+ </li>
+
+ <li>
+ <code>f(1)</code> の呼び出しで発生したゼロ除算
+ </li>
+
+ <li>
+ …
+ </li>
+
+ <li>
+ <code>f(37)</code> の呼び出しで発生したゼロ除算
+ </li>
+ </ol>
+
+ <p>
+ となっている。出力の際は <code>catch</code> したエラーの <code>getPrevious()</code> から処理を始めるので、1 番目の <code>f()</code> によるエラーは無視され、 <code>f(0)</code> によるエラー、 <code>f(1)</code> によるエラー、 <code>f(2)</code> によるエラー、と出力が進む。
+ </p>
+
+ <p>
+ <code>f()</code> に <code>0</code> を渡したときは 12 行目にある <code>match</code> の <code>0</code> でゼロ除算が起こるので、行数が 12 となったエラーが投げられる。出力部ではこれに 23 を足した数を ASCII コードとして表示しているのだった。 <code>12 + 23</code> は <code>35</code>、ASCII コードでは <code>#</code> である。これがトークンの 1文字目にあたる。
+ </p>
+ </section>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">おわりに</a></h2>
+ <p>
+ 「行数」というのはトークン文字列をデコードする対象として優れている。
+ </p>
+
+ <ul>
+ <li>
+ トークンの一部や全部が陽に現れない
+ </li>
+
+ <li>
+ <code>__LINE__</code> で容易に取得できる
+ </li>
+ </ul>
+
+ <p>
+ しかし、こういった「変な」プログラムを何度も読んだり書いたりしていると、 <code>__LINE__</code> を使うのはあまりにありきたりで退屈になる。では、他に行数を取得する手段はないか。こうして <code>Throwable</code> を思いつき、続けてエラーオブジェクトには <code>$previous</code> があることを思い出した。
+ </p>
+
+ <p>
+ 今回エラーを投げるのにゼロ除算を用いたのは、それがエラーを投げる最も短いコードだと考えたからである。もし 3バイト未満で <code>Throwable</code> なオブジェクトを投げる手段をご存じのかたがいらっしゃれば、ぜひご教示いただきたい。……と締める予定だったのだが、<code>0/0</code> のところを存在しない定数にすれば、簡単に 1バイトを達成できた。ゼロ除算している箇所はちょうど 26 箇所あるので、アルファベットにでもしておけば意味ありげで良かったかもしれない。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..12a8664a
--- /dev/null
+++ b/vhosts/blog/public/posts/2023-03-10/rewrite-this-blog-generator/index.html
@@ -0,0 +1,166 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2023 nsfisis">
+ <meta name="description" content="このブログのジェネレータを書き直したので、やったことを書き記しておく。">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>このブログのジェネレータを書き直した | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">このブログのジェネレータを書き直した</h1>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2023-03-10">2023-03-10</time>: 公開
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ このブログを構築するシステムを書き直したのは 2度目である。 元々立ち上げた当初は、静的サイトジェネレータである <a href="https://gohugo.io/">Hugo</a> を使っていた。 それを <a href="https://asciidoctor.org/">Asciidoctor</a> にいくつかのカスタムを加えた自前のジェネレータに移行したのが 2022年の11月ごろだ。 そして今回、スクラッチから書いた <a href="https://deno.land/">Deno</a> 製のジェネレータに移行した。
+ </p>
+
+ <p>
+ この記事では、移行の理由などを (主に将来の私へ向けて) 書き記しておく。
+ </p>
+ </section>
+
+ <section id="section--from-hugo-to-asciidoctor">
+ <h2><a href="#section--from-hugo-to-asciidoctor">Hugo から Asciidoctor へ</a></h2>
+ <p>
+ 最初に断っておくと、Hugo は大変に優れた静的サイトジェネレータである。移行の理由の大半は、自分でジェネレータを書きたかったからに他ならない。 実のところ、この記事を執筆している現在、自作ジェネレータは Hugo よりも機能が劣っている。 例えば、Hugo を使っていたころはサポートしていた RSS フィードの生成は、まだ実装できていない。
+ </p>
+
+ <p>
+ 移行先のフォーマットとして AsciiDoc を選んだのは、Markdown よりも表現力に優れるからである。Markdown は広く使われている軽量マークアップ言語だが、以下のような欠点を持つ。
+ </p>
+
+ <p>
+ <ul>
+ <li>
+ CommonMark では機能が貧弱である (例: 脚注、<code>id</code> 属性の付与)
+ </li>
+
+ <li>
+ 拡張記法に実装間で互換性がない
+ </li>
+
+ <li>
+ メタデータ (公開日など) を埋め込む統一された方法がない
+ </li>
+ </ul>
+ </p>
+
+ <p>
+ AsciiDoc は Markdown に比べると普及していないが、上記の欠点は克服している。
+ </p>
+
+ <p>
+ <ul>
+ <li>
+ ブログを書くのに十分な表現力がある
+ </li>
+
+ <li>
+ フォーマットを拡張するときの記法があらかじめ定められている
+ </li>
+
+ <li>
+ メタデータを埋め込む統一された方法がある
+ </li>
+ </ul>
+ </p>
+
+ <p>
+ なお、Hugo は AsciiDoc もサポートしているのだが、AsciiDoc を使う場合 Asciidoctor を別途インストールする必要があり、それならば最初から Asciidoctor でよかろうと移行を決めた。
+ </p>
+ </section>
+
+ <section id="section--from-asciidoctor-to-my-own-generator">
+ <h2><a href="#section--from-asciidoctor-to-my-own-generator">Asciidoctor から自前のジェネレータへ</a></h2>
+ <p>
+ AsciiDoc は良いフォーマットだが、私には 1点不満があった。それは、高い表現力を担保するために記号が使い倒されており、エスケープが難しいという点だ (具体例を挙げたいのだが、何だったか覚えていない)。これは、多種多様な記号類を入力する必要のある技術ブログにとっては辛い問題である。この問題を解決するため、
+ <ul>
+ <li>
+ 表現力が高く、
+ </li>
+
+ <li>
+ 文法が厳密であり、
+ </li>
+
+ <li>
+ 簡単に実装できる
+ </li>
+ </ul>
+ フォーマットが求められた。これに合致したのが、XML をベースとする <a href="https://docbook.org/">DocBook</a> (今回使っているのは、そのサブセットである <a href="https://tdg.docbook.org/tdg/sdocbook/5.1/">Simplified DocBook</a>) である。
+ </p>
+
+ <p>
+ 実は、AsciiDoc と DocBook はおおよそ互換性がある。AsciiDoc で書かれた文書は (ほぼ) 情報ロスなしに DocBook へ変換でき、逆もまたしかりである。 よって、DocBook には、AsciiDoc と同等の表現力がある。
+ </p>
+
+ <p>
+ XML の文法の厳密さについては、説明するまでもないだろう。また、単純な文法であることから実装が容易であり、事実上 Asciidoctor へロックインされる AsciiDoc とは異なり、さまざまな言語で多くのライブラリが存在する。
+ </p>
+
+ <p>
+ 今回は、XML のパース自体も自分で書いている (これは何となく書きたかったからであり、合理的な理由があるわけではない。実装はサボりまくっているので XML のコメントが使えないといった制限がある)。
+ </p>
+
+ <p>
+ XML という機械処理しやすいフォーマットを選ぶことには、機械的な変換や検査といった処理がおこないやすくなるといった利点もある。 欠点は軽量マークアップ言語と比べて冗長であることだが、書く際は補完などを用いるのでそれほど気にならない。 結局のところ、技術ブログの執筆を律速するのは調査と文章の記述であり、マークアップの手段は執筆時間に大した影響を与えない。
+ </p>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">おわりに</a></h2>
+ <p>
+ 2度のリライトを経て、記事のフォーマットとサイトジェネレータを上から下まで掌握した。 今後も改善のアイデアは多数あるので、じわじわと進めていきたいところだ。
+ </p>
+
+ <p>
+ 最後にもう一度書くのだが、Hugo は大変に優れた静的サイトジェネレータである。 無駄な拘りがなければこれを使うとよい。 私は無駄に拘ったので、ブログの記事を書く時間を潰してブログシステムを作ってしまった。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..547191b9
--- /dev/null
+++ b/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html
@@ -0,0 +1,745 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2023 nsfisis">
+ <meta name="description" content="PNG 画像として valid な範囲で最大限手抜きしたエンコーダを書く。">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PNG 画像の最小構成エンコーダを実装する | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PNG 画像の最小構成エンコーダを実装する</h1>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2023-04-01">2023-04-01</time>: 公開
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ この記事では、PNG 画像として valid な範囲で最大限手抜きしたエンコーダを書く。 PNG 画像に対応したビューアであれば読み込めるが、圧縮効率については一切考えない。 また、実装には Go 言語を使うが、Go の標準ライブラリにあるさまざまなアルゴリズム (PNG 画像に関係する範囲だと、zlib や CRC32、Adler-32 など) は使わない。
+ </p>
+ </section>
+
+ <section id="section--basic-structure-of-png">
+ <h2><a href="#section--basic-structure-of-png">PNG ファイルの基本構造</a></h2>
+ <p>
+ PNG ファイルの基本構造は次のようになっている。
+ </p>
+
+ <ol>
+ <li>
+ PNG signature
+ </li>
+
+ <li>
+ IHDR chunk
+ </li>
+
+ <li>
+ 任意個の chunk
+ </li>
+
+ <li>
+ IEND chunk
+ </li>
+ </ol>
+
+ <p>
+ Chunk には画像データを入れる IDAT chunk、パレットデータを入れる PLTE chunk、テキストデータを入れる tEXt chunk などがあるが、 今回は最小構成ということで IDAT chunk (と IHDR chunk と IEND chunk) のみを用いる。
+ </p>
+
+ <p>
+ 次節で、それぞれの具体的な構造を確認しつつ実装していく。
+ </p>
+ </section>
+
+ <section id="section--implement-png-encoder">
+ <h2><a href="#section--implement-png-encoder">PNG のエンコーダを実装する</a></h2>
+ <p>
+ 以下のソースコードをベースにする。 今回 PNG のデコーダは扱わないので、読み込みには Go の標準ライブラリ <code>image/png</code> を用いる。
+ </p>
+
+ <pre class="highlight" language="go" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">package</span> main
+
+<span class="hljs-keyword">import</span> (
+ <span class="hljs-string">&quot;image&quot;</span>
+ _ <span class="hljs-string">&quot;image/png&quot;</span>
+ <span class="hljs-string">&quot;io&quot;</span>
+ <span class="hljs-string">&quot;os&quot;</span>
+)
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
+ inFile, err := os.Open(<span class="hljs-string">&quot;input.png&quot;</span>)
+ <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
+ <span class="hljs-built_in">panic</span>(err)
+ }
+ <span class="hljs-keyword">defer</span> inFile.Close()
+
+ img, _, err := image.Decode(inFile)
+ <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
+ <span class="hljs-built_in">panic</span>(err)
+ }
+
+ outFile, err := os.Create(<span class="hljs-string">&quot;output.png&quot;</span>)
+ <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
+ <span class="hljs-built_in">panic</span>(err)
+ }
+ <span class="hljs-keyword">defer</span> outFile.Close()
+
+ writePng(outFile, img)
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writePng</span><span class="hljs-params">(w io.Writer, img image.Image)</span></span> {
+ width := <span class="hljs-type">uint32</span>(img.Bounds().Dx())
+ height := <span class="hljs-type">uint32</span>(img.Bounds().Dy())
+ writeSignature(w)
+ writeChunkIhdr(w, width, height)
+ writeChunkIdat(w, width, height, img)
+ writeChunkIend(w)
+}</code></pre>
+
+ <p>
+ 以降は、<code>writeSignature</code> や <code>writeChunkIhdr</code> などを実装していく。
+ </p>
+
+ <section id="section--implement-png-encoder--png-signature">
+ <h3><a href="#section--implement-png-encoder--png-signature">PNG signature</a></h3>
+ <p>
+ PNG signature は、PNG 画像の先頭に固定で付与されるバイト列で、8 バイトからなる。
+ </p>
+
+ <ol>
+ <li>
+ 0x89
+ </li>
+
+ <li>
+ 0x50 (ASCII コードで「P」)
+ </li>
+
+ <li>
+ 0x4E (ASCII コードで「N」)
+ </li>
+
+ <li>
+ 0x47 (ASCII コードで「G」)
+ </li>
+
+ <li>
+ 0x0D (ASCII コードで CR)
+ </li>
+
+ <li>
+ 0x0A (ASCII コードで LF)
+ </li>
+
+ <li>
+ 0x1A (ASCII コードで EOF)
+ </li>
+
+ <li>
+ 0x0A (ASCII コードで LF)
+ </li>
+ </ol>
+
+ <p>
+ CRLF や LF は、送信中に改行コードの変換が誤っておこなわれていないかどうかを検知するのに使われる。
+ </p>
+
+ <p>
+ <code>writeSignature</code> の実装はこちら:
+ </p>
+
+ <pre class="highlight" language="go" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">import</span> <span class="hljs-string">&quot;encoding/binary&quot;</span>
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeSignature</span><span class="hljs-params">(w io.Writer)</span></span> {
+ sig := [<span class="hljs-number">8</span>]<span class="hljs-type">uint8</span>{
+ <span class="hljs-number">0x89</span>,
+ <span class="hljs-number">0x50</span>, <span class="hljs-comment">// P</span>
+ <span class="hljs-number">0x4E</span>, <span class="hljs-comment">// N</span>
+ <span class="hljs-number">0x47</span>, <span class="hljs-comment">// G</span>
+ <span class="hljs-number">0x0D</span>, <span class="hljs-comment">// CR</span>
+ <span class="hljs-number">0x0A</span>, <span class="hljs-comment">// LF</span>
+ <span class="hljs-number">0x1A</span>, <span class="hljs-comment">// EOF (^Z)</span>
+ <span class="hljs-number">0x0A</span>, <span class="hljs-comment">// LF</span>
+ }
+ binary.Write(w, binary.BigEndian, sig)
+}</code></pre>
+
+ <p>
+ <code>encoding/binary</code> パッケージの <code>binary.Write</code> を使い、固定の 8 バイトを書き込む。
+ </p>
+ </section>
+
+ <section id="section--implement-png-encoder--structure-of-chunk">
+ <h3><a href="#section--implement-png-encoder--structure-of-chunk">Chunk の構造</a></h3>
+ <p>
+ IHDR chunk に進む前に、chunk 一般の構造を確認する。
+ </p>
+
+ <ol>
+ <li>
+ Length: chunk data のバイト長 (符号なし 4 バイト整数)
+ </li>
+
+ <li>
+ Chunk type: chunk の種類を示す 4 バイトからなる名前
+ </li>
+
+ <li>
+ Chunk data: 実際のデータ。0 バイトでもよい
+ </li>
+
+ <li>
+ CRC: chunk type と chunk data の CRC (符号なし 4 バイト整数)
+ </li>
+ </ol>
+
+ <p>
+ CRC (Cyclic Redundancy Check) は誤り検出符号の一種。Go 言語では <code>hash/crc32</code> パッケージにあるが、今回はこれも自前で実装する。PNG の仕様書に C 言語のサンプルコードが載っている (<a href="https://www.w3.org/TR/png/#D-CRCAppendix">D. Sample CRC implementation</a>) ので、これを Go に移植する。
+ </p>
+
+ <pre class="highlight" language="go" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">var</span> (
+ crcTable [<span class="hljs-number">256</span>]<span class="hljs-type">uint32</span>
+ crcTableComputed <span class="hljs-type">bool</span>
+)
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">makeCrcTable</span><span class="hljs-params">()</span></span> {
+ <span class="hljs-keyword">for</span> n := <span class="hljs-number">0</span>; n &lt; <span class="hljs-number">256</span>; n++ {
+ c := <span class="hljs-type">uint32</span>(n)
+ <span class="hljs-keyword">for</span> k := <span class="hljs-number">0</span>; k &lt; <span class="hljs-number">8</span>; k++ {
+ <span class="hljs-keyword">if</span> (c &amp; <span class="hljs-number">1</span>) != <span class="hljs-number">0</span> {
+ c = <span class="hljs-number">0xEDB88320</span> ^ (c &gt;&gt; <span class="hljs-number">1</span>)
+ } <span class="hljs-keyword">else</span> {
+ c = c &gt;&gt; <span class="hljs-number">1</span>
+ }
+ }
+ crcTable[n] = c
+ }
+ crcTableComputed = <span class="hljs-literal">true</span>
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateCrc</span><span class="hljs-params">(crc <span class="hljs-type">uint32</span>, buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
+ <span class="hljs-keyword">if</span> !crcTableComputed {
+ makeCrcTable()
+ }
+
+ c := crc
+ <span class="hljs-keyword">for</span> n := <span class="hljs-number">0</span>; n &lt; <span class="hljs-built_in">len</span>(buf); n++ {
+ c = crcTable[(c^<span class="hljs-type">uint32</span>(buf[n]))&amp;<span class="hljs-number">0xFF</span>] ^ (c &gt;&gt; <span class="hljs-number">8</span>)
+ }
+ <span class="hljs-keyword">return</span> c
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">crc</span><span class="hljs-params">(buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
+ <span class="hljs-keyword">return</span> updateCrc(<span class="hljs-number">0xFFFFFFFF</span>, buf) ^ <span class="hljs-number">0xFFFFFFFF</span>
+}</code></pre>
+
+ <p>
+ できた <code>crc</code> 関数を使って、chunk 一般を書き込む関数も用意しておこう。
+ </p>
+
+ <pre class="highlight" language="go" linenumbering="unnumbered"><code class="highlight"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunk</span><span class="hljs-params">(w io.Writer, chunkType <span class="hljs-type">string</span>, data []<span class="hljs-type">byte</span>)</span></span> {
+ typeAndData := <span class="hljs-built_in">make</span>([]<span class="hljs-type">byte</span>, <span class="hljs-number">0</span>, <span class="hljs-built_in">len</span>(chunkType)+<span class="hljs-built_in">len</span>(data))
+ typeAndData = <span class="hljs-built_in">append</span>(typeAndData, []<span class="hljs-type">byte</span>(chunkType)...)
+ typeAndData = <span class="hljs-built_in">append</span>(typeAndData, data...)
+
+ binary.Write(w, binary.BigEndian, <span class="hljs-type">uint32</span>(<span class="hljs-built_in">len</span>(data)))
+ binary.Write(w, binary.BigEndian, typeAndData)
+ binary.Write(w, binary.BigEndian, crc(typeAndData))
+}</code></pre>
+
+ <p>
+ 仕様どおり、<code>chunkType</code> と <code>data</code> から CRC を計算し、<code>data</code> の長さと合わせて書き込んでいる。 PNG では基本的に big endian を使うことに注意する。
+ </p>
+
+ <p>
+ 準備ができたところで、具体的な chunk をエンコードしていく。
+ </p>
+ </section>
+
+ <section id="section--implement-png-encoder--ihdr-chunk">
+ <h3><a href="#section--implement-png-encoder--ihdr-chunk">IHDR chunk</a></h3>
+ <p>
+ IHDR chunk は最初に配置される chunk である。次のようなデータからなる。
+ </p>
+
+ <ol>
+ <li>
+ 画像の幅 (符号なし 4 バイト整数)
+ </li>
+
+ <li>
+ 画像の高さ (符号なし 4 バイト整数)
+ </li>
+
+ <li>
+ ビット深度 (符号なし 1 バイト整数)
+ <ul>
+ <li>
+ 1 色に使うビット数。1 ピクセルに 24 bit 使う truecolor 画像では 8 になる
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ 色タイプ (符号なし 1 バイト整数)
+ <ul>
+ <li>
+ 0: グレースケール
+ </li>
+
+ <li>
+ 2: Truecolor (今回はこれに決め打ち)
+ </li>
+
+ <li>
+ 3: パレットのインデックス
+ </li>
+
+ <li>
+ 4: グレースケール + アルファ
+ </li>
+
+ <li>
+ 6: Truecolor + アルファ
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ 圧縮方式 (符号なし 1 バイト整数)
+ <ul>
+ PNG の仕様書に 0 しか定義されていないので 0 で固定
+ </ul>
+ </li>
+
+ <li>
+ フィルタ方式 (符号なし 1 バイト整数)
+ <ul>
+ PNG の仕様書に 0 しか定義されていないので 0 で固定
+ </ul>
+ </li>
+
+ <li>
+ インターレース方式 (符号なし 1 バイト整数)
+ <ul>
+ 今回はインターレースしないので 0
+ </ul>
+ </li>
+ </ol>
+
+ <p>
+ 今回ほとんどのデータは決め打ちするので、データに応じて変わるのは width と height だけになる。コードは次のようになる。
+ </p>
+
+ <pre class="highlight" language="go" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">import</span> <span class="hljs-string">&quot;bytes&quot;</span>
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunkIhdr</span><span class="hljs-params">(w io.Writer, width, height <span class="hljs-type">uint32</span>)</span></span> {
+ <span class="hljs-keyword">var</span> buf bytes.Buffer
+ binary.Write(&amp;buf, binary.BigEndian, width)
+ binary.Write(&amp;buf, binary.BigEndian, height)
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">8</span>))
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">2</span>))
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
+
+ writeChunk(w, <span class="hljs-string">&quot;IHDR&quot;</span>, buf.Bytes())
+}</code></pre>
+ </section>
+
+ <section id="section--implement-png-encoder--idat-chunk">
+ <h3><a href="#section--implement-png-encoder--idat-chunk">IDAT chunk</a></h3>
+ <p>
+ IDAT chunk は、実際の画像データが格納された chunk である。IDAT chunk は deflate アルゴリズムにより圧縮され、zlib 形式で格納される。
+ </p>
+
+ <section id="section--implement-png-encoder--idat-chunk--zlib">
+ <h4><a href="#section--implement-png-encoder--idat-chunk--zlib">Zlib</a></h4>
+ <p>
+ まずは zlib について確認する。おおよそ次のような構造になっている。
+ </p>
+
+ <ol>
+ <li>
+ 固定で 0x78 (符号なし 1 バイト整数)
+ </li>
+
+ <li>
+ 固定で 0x01 (符号なし 1 バイト整数)
+ </li>
+
+ <li>
+ データ
+ </li>
+
+ <li>
+ データの Adler-32
+ </li>
+ </ol>
+
+ <p>
+ 最初の 2 バイトにも意味はあるが、PNG では固定で構わない。
+ </p>
+
+ <p>
+ Adler-32 も CRC と同じく誤り検出符号である。こちらも zlib の仕様書に C 言語でサンプルコードが記載されている (<a href="https://www.rfc-editor.org/rfc/rfc1950#section-9">9. Appendix: Sample code</a>) ので、Go に移植する。
+ </p>
+
+ <pre class="highlight" language="go" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">const</span> adler32Base = <span class="hljs-number">65521</span>
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateAdler32</span><span class="hljs-params">(adler <span class="hljs-type">uint32</span>, buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
+ s1 := adler &amp; <span class="hljs-number">0xFFFF</span>
+ s2 := (adler &gt;&gt; <span class="hljs-number">16</span>) &amp; <span class="hljs-number">0xFFFF</span>
+
+ <span class="hljs-keyword">for</span> n := <span class="hljs-number">0</span>; n &lt; <span class="hljs-built_in">len</span>(buf); n++ {
+ s1 = (s1 + <span class="hljs-type">uint32</span>(buf[n])) % adler32Base
+ s2 = (s2 + s1) % adler32Base
+ }
+ <span class="hljs-keyword">return</span> (s2 &lt;&lt; <span class="hljs-number">16</span>) + s1
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">adler32</span><span class="hljs-params">(buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
+ <span class="hljs-keyword">return</span> updateAdler32(<span class="hljs-number">1</span>, buf)
+}</code></pre>
+
+ <p>
+ 「データ」の部分には圧縮したデータが入るのだが、真面目に deflate アルゴリズムを実装する必要はない。Zlib には無圧縮のデータブロックを格納することができるので、これを使う。本来は、データの圧縮効率の悪いランダムなデータをそのまま格納するためのものだが、今回は deflate の実装をサボるために使う。
+ </p>
+
+ <p>
+ 1 つの無圧縮ブロックには 65535 (2<sup>16</sup> - 1) バイトまで格納できる。それぞれのブロックは次のような構成になっている。
+ </p>
+
+ <ol>
+ <li>
+ 最終ブロックなら 1、そうでなければ 0 (符号なし 1 バイト整数)
+ </li>
+
+ <li>
+ ブロックのバイト長 (符号なし 2 バイト整数)
+ </li>
+
+ <li>
+ ブロックのバイト長の 1 の補数、あるいはビット反転 (符号なし 2 バイト整数)
+ </li>
+
+ <li>
+ データ (最大 65535 バイト)
+ </li>
+ </ol>
+
+ <p>
+ 実際にこの手抜き zlib を実装したものがこちら:
+ </p>
+
+ <pre class="highlight" language="go" linenumbering="unnumbered"><code class="highlight"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">encodeZlib</span><span class="hljs-params">(data []<span class="hljs-type">byte</span>)</span></span> []<span class="hljs-type">byte</span> {
+ <span class="hljs-keyword">var</span> buf bytes.Buffer
+
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0x78</span>))
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0x01</span>))
+ blockSize := <span class="hljs-number">65535</span>
+ isFinalBlock := <span class="hljs-literal">false</span>
+ <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; !isFinalBlock; i++ {
+ <span class="hljs-keyword">var</span> block []<span class="hljs-type">byte</span>
+ <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(data) &lt;= (i+<span class="hljs-number">1</span>)*blockSize {
+ block = data[i*blockSize:]
+ isFinalBlock = <span class="hljs-literal">true</span>
+ } <span class="hljs-keyword">else</span> {
+ block = data[i*blockSize : (i+<span class="hljs-number">1</span>)*blockSize]
+ }
+ binary.Write(&amp;buf, binary.BigEndian, isFinalBlock)
+ binary.Write(&amp;buf, binary.LittleEndian, <span class="hljs-type">uint16</span>(<span class="hljs-built_in">len</span>(block)))
+ binary.Write(&amp;buf, binary.LittleEndian, <span class="hljs-type">uint16</span>(^<span class="hljs-built_in">len</span>(block)))
+ binary.Write(&amp;buf, binary.LittleEndian, block)
+ }
+ binary.Write(&amp;buf, binary.BigEndian, adler32(data))
+
+ <span class="hljs-keyword">return</span> buf.Bytes()
+}</code></pre>
+ </section>
+
+ <section id="section--implement-png-encoder--idat-chunk--image-data">
+ <h4><a href="#section--implement-png-encoder--idat-chunk--image-data">画像データ</a></h4>
+ <p>
+ では次に、zlib 形式で格納するデータを用意する。PNG 画像は次のような順にスキャンする。 画像の左上のピクセルから同じ行を横にスキャンしていき、一番右まで到達したら次の行の左に向かう。 右下のピクセルまで行けば終わり。要は Z 字型に進んでいく。
+ </p>
+
+ <p>
+ また、それぞれの行の先頭には、圧縮のためのフィルタタイプを指定する。 ただ、今回はその実装を省略するために、常にフィルタ 0 (何も加工しない) を使う。
+ </p>
+
+ <p>
+ 先ほどの <code>encodeZlib</code> も使って実際に実装したものがこちら:
+ </p>
+
+ <pre class="highlight" language="go" linenumbering="unnumbered"><code class="highlight"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunkIdat</span><span class="hljs-params">(w io.Writer, width, height <span class="hljs-type">uint32</span>, img image.Image)</span></span> {
+ <span class="hljs-keyword">var</span> pixels bytes.Buffer
+ <span class="hljs-keyword">for</span> y := <span class="hljs-type">uint32</span>(<span class="hljs-number">0</span>); y &lt; height; y++ {
+ binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
+ <span class="hljs-keyword">for</span> x := <span class="hljs-type">uint32</span>(<span class="hljs-number">0</span>); x &lt; width; x++ {
+ r, g, b, _ := img.At(<span class="hljs-type">int</span>(x), <span class="hljs-type">int</span>(y)).RGBA()
+ binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(r))
+ binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(g))
+ binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(b))
+ }
+ }
+
+ writeChunk(w, <span class="hljs-string">&quot;IDAT&quot;</span>, encodeZlib(pixels.Bytes()))
+}</code></pre>
+ </section>
+ </section>
+
+ <section id="section--implement-png-encoder--iend-chunk">
+ <h3><a href="#section--implement-png-encoder--iend-chunk">IEND chunk</a></h3>
+ <p>
+ 最後に IEND chunk を書き込む。これは PNG 画像の最後に配置される chunk で、PNG のデコーダはこの chunk に出会うとそこでデコードを停止する。
+ </p>
+
+ <p>
+ 特に追加のデータはなく、必要なのは chunk type の <code>IEND</code> くらいなので実装は簡単:
+ </p>
+
+ <pre class="highlight" language="go" linenumbering="unnumbered"><code class="highlight"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunkIend</span><span class="hljs-params">(w io.Writer)</span></span> {
+ writeChunk(w, <span class="hljs-string">&quot;IEND&quot;</span>, <span class="hljs-literal">nil</span>)
+}</code></pre>
+ </section>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">おわりに</a></h2>
+ <p>
+ 最後に全ソースコードを再掲しておく。
+ </p>
+
+ <pre class="highlight" language="go" linenumbering="unnumbered"><code class="highlight"><span class="hljs-keyword">package</span> main
+
+<span class="hljs-keyword">import</span> (
+ <span class="hljs-string">&quot;bytes&quot;</span>
+ <span class="hljs-string">&quot;encoding/binary&quot;</span>
+ <span class="hljs-string">&quot;image&quot;</span>
+ _ <span class="hljs-string">&quot;image/png&quot;</span>
+ <span class="hljs-string">&quot;io&quot;</span>
+ <span class="hljs-string">&quot;os&quot;</span>
+)
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
+ inFile, err := os.Open(<span class="hljs-string">&quot;input.png&quot;</span>)
+ <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
+ <span class="hljs-built_in">panic</span>(err)
+ }
+ <span class="hljs-keyword">defer</span> inFile.Close()
+
+ img, _, err := image.Decode(inFile)
+ <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
+ <span class="hljs-built_in">panic</span>(err)
+ }
+
+ outFile, err := os.Create(<span class="hljs-string">&quot;output.png&quot;</span>)
+ <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
+ <span class="hljs-built_in">panic</span>(err)
+ }
+ <span class="hljs-keyword">defer</span> outFile.Close()
+
+ writePng(outFile, img)
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writePng</span><span class="hljs-params">(w io.Writer, img image.Image)</span></span> {
+ width := <span class="hljs-type">uint32</span>(img.Bounds().Dx())
+ height := <span class="hljs-type">uint32</span>(img.Bounds().Dy())
+ writeSignature(w)
+ writeChunkIhdr(w, width, height)
+ writeChunkIdat(w, width, height, img)
+ writeChunkIend(w)
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeSignature</span><span class="hljs-params">(w io.Writer)</span></span> {
+ sig := [<span class="hljs-number">8</span>]<span class="hljs-type">uint8</span>{
+ <span class="hljs-number">0x89</span>,
+ <span class="hljs-number">0x50</span>, <span class="hljs-comment">// P</span>
+ <span class="hljs-number">0x4E</span>, <span class="hljs-comment">// N</span>
+ <span class="hljs-number">0x47</span>, <span class="hljs-comment">// G</span>
+ <span class="hljs-number">0x0D</span>, <span class="hljs-comment">// CR</span>
+ <span class="hljs-number">0x0A</span>, <span class="hljs-comment">// LF</span>
+ <span class="hljs-number">0x1A</span>, <span class="hljs-comment">// EOF (^Z)</span>
+ <span class="hljs-number">0x0A</span>, <span class="hljs-comment">// LF</span>
+ }
+ binary.Write(w, binary.BigEndian, sig)
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunkIhdr</span><span class="hljs-params">(w io.Writer, width, height <span class="hljs-type">uint32</span>)</span></span> {
+ <span class="hljs-keyword">var</span> buf bytes.Buffer
+ binary.Write(&amp;buf, binary.BigEndian, width)
+ binary.Write(&amp;buf, binary.BigEndian, height)
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">8</span>))
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">2</span>))
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
+
+ writeChunk(w, <span class="hljs-string">&quot;IHDR&quot;</span>, buf.Bytes())
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunkIdat</span><span class="hljs-params">(w io.Writer, width, height <span class="hljs-type">uint32</span>, img image.Image)</span></span> {
+ <span class="hljs-keyword">var</span> pixels bytes.Buffer
+ <span class="hljs-keyword">for</span> y := <span class="hljs-type">uint32</span>(<span class="hljs-number">0</span>); y &lt; height; y++ {
+ binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
+ <span class="hljs-keyword">for</span> x := <span class="hljs-type">uint32</span>(<span class="hljs-number">0</span>); x &lt; width; x++ {
+ r, g, b, _ := img.At(<span class="hljs-type">int</span>(x), <span class="hljs-type">int</span>(y)).RGBA()
+ binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(r))
+ binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(g))
+ binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(b))
+ }
+ }
+
+ writeChunk(w, <span class="hljs-string">&quot;IDAT&quot;</span>, encodeZlib(pixels.Bytes()))
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">encodeZlib</span><span class="hljs-params">(data []<span class="hljs-type">byte</span>)</span></span> []<span class="hljs-type">byte</span> {
+ <span class="hljs-keyword">var</span> buf bytes.Buffer
+
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0x78</span>))
+ binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0x01</span>))
+ blockSize := <span class="hljs-number">65535</span>
+ isFinalBlock := <span class="hljs-literal">false</span>
+ <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; !isFinalBlock; i++ {
+ <span class="hljs-keyword">var</span> block []<span class="hljs-type">byte</span>
+ <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(data) &lt;= (i+<span class="hljs-number">1</span>)*blockSize {
+ block = data[i*blockSize:]
+ isFinalBlock = <span class="hljs-literal">true</span>
+ } <span class="hljs-keyword">else</span> {
+ block = data[i*blockSize : (i+<span class="hljs-number">1</span>)*blockSize]
+ }
+ binary.Write(&amp;buf, binary.BigEndian, isFinalBlock)
+ binary.Write(&amp;buf, binary.LittleEndian, <span class="hljs-type">uint16</span>(<span class="hljs-built_in">len</span>(block)))
+ binary.Write(&amp;buf, binary.LittleEndian, <span class="hljs-type">uint16</span>(^<span class="hljs-built_in">len</span>(block)))
+ binary.Write(&amp;buf, binary.LittleEndian, block)
+ }
+ binary.Write(&amp;buf, binary.BigEndian, adler32(data))
+
+ <span class="hljs-keyword">return</span> buf.Bytes()
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunkIend</span><span class="hljs-params">(w io.Writer)</span></span> {
+ writeChunk(w, <span class="hljs-string">&quot;IEND&quot;</span>, <span class="hljs-literal">nil</span>)
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunk</span><span class="hljs-params">(w io.Writer, chunkType <span class="hljs-type">string</span>, data []<span class="hljs-type">byte</span>)</span></span> {
+ typeAndData := <span class="hljs-built_in">make</span>([]<span class="hljs-type">byte</span>, <span class="hljs-number">0</span>, <span class="hljs-built_in">len</span>(chunkType)+<span class="hljs-built_in">len</span>(data))
+ typeAndData = <span class="hljs-built_in">append</span>(typeAndData, []<span class="hljs-type">byte</span>(chunkType)...)
+ typeAndData = <span class="hljs-built_in">append</span>(typeAndData, data...)
+
+ binary.Write(w, binary.BigEndian, <span class="hljs-type">uint32</span>(<span class="hljs-built_in">len</span>(data)))
+ binary.Write(w, binary.BigEndian, typeAndData)
+ binary.Write(w, binary.BigEndian, crc(typeAndData))
+}
+
+<span class="hljs-keyword">var</span> (
+ crcTable [<span class="hljs-number">256</span>]<span class="hljs-type">uint32</span>
+ crcTableComputed <span class="hljs-type">bool</span>
+)
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">makeCrcTable</span><span class="hljs-params">()</span></span> {
+ <span class="hljs-keyword">for</span> n := <span class="hljs-number">0</span>; n &lt; <span class="hljs-number">256</span>; n++ {
+ c := <span class="hljs-type">uint32</span>(n)
+ <span class="hljs-keyword">for</span> k := <span class="hljs-number">0</span>; k &lt; <span class="hljs-number">8</span>; k++ {
+ <span class="hljs-keyword">if</span> (c &amp; <span class="hljs-number">1</span>) != <span class="hljs-number">0</span> {
+ c = <span class="hljs-number">0xEDB88320</span> ^ (c &gt;&gt; <span class="hljs-number">1</span>)
+ } <span class="hljs-keyword">else</span> {
+ c = c &gt;&gt; <span class="hljs-number">1</span>
+ }
+ }
+ crcTable[n] = c
+ }
+ crcTableComputed = <span class="hljs-literal">true</span>
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateCrc</span><span class="hljs-params">(crc <span class="hljs-type">uint32</span>, buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
+ <span class="hljs-keyword">if</span> !crcTableComputed {
+ makeCrcTable()
+ }
+
+ c := crc
+ <span class="hljs-keyword">for</span> n := <span class="hljs-number">0</span>; n &lt; <span class="hljs-built_in">len</span>(buf); n++ {
+ c = crcTable[(c^<span class="hljs-type">uint32</span>(buf[n]))&amp;<span class="hljs-number">0xFF</span>] ^ (c &gt;&gt; <span class="hljs-number">8</span>)
+ }
+ <span class="hljs-keyword">return</span> c
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">crc</span><span class="hljs-params">(buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
+ <span class="hljs-keyword">return</span> updateCrc(<span class="hljs-number">0xFFFFFFFF</span>, buf) ^ <span class="hljs-number">0xFFFFFFFF</span>
+}
+
+<span class="hljs-keyword">const</span> adler32Base = <span class="hljs-number">65521</span>
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateAdler32</span><span class="hljs-params">(adler <span class="hljs-type">uint32</span>, buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
+ s1 := adler &amp; <span class="hljs-number">0xFFFF</span>
+ s2 := (adler &gt;&gt; <span class="hljs-number">16</span>) &amp; <span class="hljs-number">0xFFFF</span>
+
+ <span class="hljs-keyword">for</span> n := <span class="hljs-number">0</span>; n &lt; <span class="hljs-built_in">len</span>(buf); n++ {
+ s1 = (s1 + <span class="hljs-type">uint32</span>(buf[n])) % adler32Base
+ s2 = (s2 + s1) % adler32Base
+ }
+ <span class="hljs-keyword">return</span> (s2 &lt;&lt; <span class="hljs-number">16</span>) + s1
+}
+
+<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">adler32</span><span class="hljs-params">(buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
+ <span class="hljs-keyword">return</span> updateAdler32(<span class="hljs-number">1</span>, buf)
+}</code></pre>
+ </section>
+
+ <section id="section--references">
+ <h2><a href="#section--references">参考</a></h2>
+ <ul>
+ <li>
+ <a href="https://www.w3.org/TR/png">Portable Network Graphics (PNG) Specification (Third Edition)</a>
+ </li>
+
+ <li>
+ <a href="https://www.rfc-editor.org/rfc/rfc1950">ZLIB Compressed Data Format Specification version 3.3</a>
+ </li>
+ </ul>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..6350ee40
--- /dev/null
+++ b/vhosts/blog/public/posts/2023-04-04/phperkaigi-2023-report/index.html
@@ -0,0 +1,307 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2023 nsfisis">
+ <meta name="description" content="2023-03-23 から 2023-03-25 にかけて開催された、PHPerKaigi 2023 に参加した。">
+ <meta name="keywords" content="カンファレンス,PHP,PHPerKaigi">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHPerKaigi 2023 参加レポ | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHPerKaigi 2023 参加レポ</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/conference/">カンファレンス</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/phperkaigi/">PHPerKaigi</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2023-04-04">2023-04-04</time>: 公開
+ </li>
+ <li class="revision">
+ <time datetime="2023-06-28">2023-06-28</time>: トークセッションの記事版の執筆を中止
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ 2023-03-23 から 2023-03-25 にかけて開催された、<a href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</a> に参加した。 今年は 2つのセッションのスピーカーとして、また、当日スタッフとして参加した。
+ </p>
+
+ <p>
+ 昨年、一昨年の参加レポはこちら:
+ </p>
+
+ <ul>
+ <li>
+ <a href="/posts/2022-05-01/phperkaigi-2022/">PHPerKaigi 2022</a>
+ </li>
+
+ <li>
+ <a href="/posts/2021-03-30/phperkaigi-2021/">PHPerKaigi 2021</a>
+ </li>
+ </ul>
+ </section>
+
+ <section id="section--as-speaker">
+ <h2><a href="#section--as-speaker">スピーカーとして</a></h2>
+ <p>
+ これまでとの最大の違いとして、今回はスピーカーとして登壇した。まずはそれについて書く。2つのセッションで登壇した。
+ </p>
+
+ <ul>
+ <li>
+ 詳説「参照」:PHP 処理系の実装から参照を理解する
+ <ul>
+ <li>
+ <a href="https://fortee.jp/phperkaigi-2023/proposal/95e4dd94-5fc7-40fe-9e1a-230e36404cbe">プロポーザル</a>
+ </li>
+
+ <li>
+ <a href="/slides/2023-03-24/phperkaigi-2023/">スライド</a>
+ </li>
+
+ <li>
+ 解説記事 (執筆中) → 追記: 記事版の執筆は諦めた
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ PHPerチャレンジ解説セッション - デジタルサーカス株式会社
+ <ul>
+ <li>
+ <a href="https://fortee.jp/phperkaigi-2023/proposal/524c9dca-1d70-4b32-a939-9c73ffe5cb48">プロポーザル</a>
+ </li>
+
+ <li>
+ <a href="/slides/2023-03-25/phperkaigi-2023-tokens/">スライド</a>
+ </li>
+
+ <li>
+ 解説記事 (執筆中) → 追記: 記事版の執筆は諦めた
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>
+ PHPer チャレンジの話については後述する。 参照については、PHP を書き始めた頃からずっと疑問に思っていたので、仕組みを理解する良い機会となった。
+ </p>
+ </section>
+
+ <section id="section--as-staff">
+ <h2><a href="#section--as-staff">当日スタッフとして</a></h2>
+ <p>
+ 今回はスピーカーのみならず当日スタッフとしても参加した。 カンファレンスのスタッフとしての参加は初めてだったが、初参加のスタッフでもスムーズに作業ができるような仕組みが整えられていた。
+ </p>
+
+ <p>
+ PHPerKaigi は一般参加者の目線でもよくできたカンファレンスだなあという印象だったのだが、よりその思いを強くした。 なんとスタッフにとってもよくできたカンファレンスなのである。
+ </p>
+
+ <p>
+ 反省点は私自身の最大 HP がまったく足りていなかったことで、次の機会には最後まで動けるようにしたいところである。
+ </p>
+ </section>
+
+ <section id="section--as-attendee">
+ <h2><a href="#section--as-attendee">参加者として</a></h2>
+ <section id="section--as-attendee--recommended-sessions">
+ <h3><a href="#section--as-attendee--recommended-sessions">おすすめセッション</a></h3>
+ <p>
+ 5つのセッションを厳選した。
+ </p>
+
+ <p>
+ <a href="https://fortee.jp/phperkaigi-2023/proposal/f7f2f18a-e6b0-47e4-ade0-e324f72428ae">ブラウザの向こう側で「200 OK」を返すまでに何が起きているのか調べてみた</a>
+ </p>
+
+ <p>
+ Web に関わるなら、バックエンドでもフロントエンドでも知っておいてほしい知識。 タイトルを見て「こんな話だろうな」と想像がつくレベルなら見なくてもいいかも。
+ </p>
+
+ <p>
+ <a href="https://fortee.jp/phperkaigi-2023/proposal/280706e0-7158-4237-8202-c9d64330b96f">PHPで学ぶ &quot;Cacheの距離&quot; の話</a>
+ </p>
+
+ <p>
+ これも上セッションと同様に、基礎を抑えられる良いセッション。
+ </p>
+
+ <p>
+ <a href="https://fortee.jp/phperkaigi-2023/proposal/ad3ba31c-0214-4557-a0df-3755db8ed8cc">防衛的 PHP: 多様性を生き抜くための PHP 入門</a>
+ </p>
+
+ <p>
+ 静的解析ツールの話。静的解析は PHP のみならず最近の動的言語の一大潮流なので、逃れられない。
+ </p>
+
+ <p>
+ <a href="https://fortee.jp/phperkaigi-2023/proposal/e00788a4-ef25-49ee-b254-9d2b53e19633">PHPの最高機能、配列を捨てよう!!</a>
+ </p>
+
+ <p>
+ 実はこれも上のセッションと同様の話。 PHP の静的解析ツールは配列にも (無理矢理) 型が付けられるものが多いが、実行時にも検査できるという点において専用のクラスを作る方が優れている。
+ </p>
+
+ <p>
+ <a href="https://fortee.jp/phperkaigi-2023/proposal/7e212cb2-be37-43e8-b6ee-5236d259fcbf">時間を気にせず普通にカンニングもしつつ ISUCON12 本選問題を PHP でやってみる</a>
+ </p>
+
+ <p>
+ 個人的に最も楽しみにしていたセッションであり、今回のモリアガリトーク賞 (盛り上がったセッションに運営側から贈られる賞) でもある。 ネタバレになるが、最終的に (Go で実装された) 本戦優勝スコアを超えている。
+ </p>
+ </section>
+
+ <section id="section--as-attendee--phper-challenge">
+ <h3><a href="#section--as-attendee--phper-challenge">PHPer チャレンジ</a></h3>
+ <p>
+ 昨年に引き続き、弊社デジタルサーカス株式会社からのトークン問題の作題を担当した。 また、今年はさらに作成した問題を解説するセッションにも登壇した。 今年のトークンは、昨年の PHPerKaigi 2022 が終わった段階から作り始め、約半年かけて制作した。
+ </p>
+
+ <p>
+ 問題の制作中は大変楽しかったが、まあやりすぎた。 いかに超絶技巧を凝らすかに注力してしまい、解く楽しさという観点を失ってしまったきらいがある。
+ </p>
+
+ <p>
+ (WIP: 解説ブログ記事執筆中。終わったらここにリンク)
+ </p>
+ </section>
+
+ <section id="section--as-attendee--random-thoughts">
+ <h3><a href="#section--as-attendee--random-thoughts">雑多な感想</a></h3>
+ <p>
+ なんかいろいろ。
+ </p>
+
+ <ul>
+ <li>
+ マカロンおいしかった
+ </li>
+
+ <li>
+ \ペチパー/
+ </li>
+
+ <li>
+ 名札便利
+ </li>
+
+ <li>
+ \ペチパー/
+ </li>
+
+ <li>
+ 傘袋便利
+ </li>
+
+ <li>
+ \ペチパー/
+ </li>
+
+ <li>
+ パーカーのデザイン良き
+ </li>
+ </ul>
+
+ <p>
+ (あとから見返して自分でもわけがわからなくなりそうなので書いておくと、会場に入場する際に名札をタッチすると小桜エツコさんの声で「ペチパー」という音声が流れるギミックがあった)
+ </p>
+ </section>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">おわりに</a></h2>
+ <p>
+ <a href="/posts/2022-05-01/phperkaigi-2022/#section--next-year">去年の参加レポ</a>では、来年の目標として次を挙げた。
+ </p>
+
+ <blockquote>
+ <ul>
+ <li>
+ プロポーザルを出す
+ </li>
+
+ <li>
+ PHPer チャレンジのトークン問題を 5題作成する
+ </li>
+
+ <li>
+ 現地に行く
+ </li>
+
+ <li>
+ PHPer チャレンジで圧勝する
+ </li>
+ </ul>
+ </blockquote>
+
+ <p>
+ プロポーザルに関しては採択されて登壇できたし、PHPer チャレンジは解説もおこなった。また、現地に行くだけでなく、当日スタッフとして参加した。 4つ目の PHPer チャレンジに関しては、今年は参加していない。 スタッフをやりながらだと入力する時間も探す時間も取れそうになかったのと、スタッフをやっている関係で少しだけ早く入手してしまうトークンがいくつか存在していたため。
+ </p>
+
+ <p>
+ カンファレンス全体の感想についてだが、大規模なカンファレンスにオフラインで参加するのは今回が初めてだったので、その話をしたい。
+ </p>
+
+ <p>
+ オンラインとオフラインだと体験が別物になる。そもそもが似て非なるものなのだ。 向き不向きはあるだろうが、オンラインしか参加したことのないという方は、一度現地参加してみてはいかがだろうか。
+ </p>
+
+ <p>
+ さて、参加レポは去年も一昨年もこの言葉で締め括っているので、今年もそれで終わろうと思う。
+ </p>
+
+ <p>
+ ではまた来年。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
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
new file mode 100644
index 00000000..315816c1
--- /dev/null
+++ b/vhosts/blog/public/posts/2023-06-25/phpconfuk-2023-report/index.html
@@ -0,0 +1,161 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2023 nsfisis">
+ <meta name="description" content="2023-06-24 に開催された、PHP カンファレンス福岡に参加した。">
+ <meta name="keywords" content="カンファレンス,PHP,PHP カンファレンス福岡">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHP カンファレンス福岡 2023 参加レポ | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHP カンファレンス福岡 2023 参加レポ</h1>
+ <ul class="post-tags">
+ <li class="tag">
+ <a href="/tags/conference/">カンファレンス</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+ <li class="tag">
+ <a href="/tags/phpconfuk/">PHP カンファレンス福岡</a>
+ </li>
+ </ul>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <li class="revision">
+ <time datetime="2023-06-25">2023-06-25</time>: 公開
+ </li>
+ </ol>
+ </section>
+ <section id="section--intro">
+ <h2><a href="#section--intro">はじめに</a></h2>
+ <p>
+ 2023-06-24 に開催された、<a href="https://phpcon.fukuoka.jp/2023/">PHP カンファレンス福岡 2023</a>に参加した。 また、その前日に催された、<a href="https://connpass.com/event/282285/">非公式の前夜祭</a>にも参加した。 前夜祭では、15分の登壇もおこなった。<a href="/slides/2023-06-23/phpconfuk-2023-eve/">登壇の方の資料はこちら。</a>
+ </p>
+ </section>
+
+ <section id="section--sessions-thoughts">
+ <h2><a href="#section--sessions-thoughts">セッションの感想</a></h2>
+ <section id="section--sessions-thoughts--eve">
+ <h3><a href="#section--sessions-thoughts--eve">前夜祭</a></h3>
+ <p>
+ ※セッションの題名と発表者名は、<a href="https://connpass.com/event/282285/">前夜祭イベントの connpass ページ</a>から引用。
+ </p>
+
+ <ul>
+ <li>
+ スクラム(の一部)を導入してよくなったこと (asumikam さん)
+ <ul>
+ <li>
+ スクラムの「一部」を導入されたということでしたが、理想的な形で改善が進んでいるように見受けられました。 特に、ブランチ運用やデプロイ頻度、フィードバックサイクルに大きく変化が起きているのは驚くべき成果だと感じました。
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ 地方の小さな勉強会を一番の活動舞台にする (tomio さん)
+ <ul>
+ <li>
+ すさまじいほどの「熱」を感じました。 私自身、最近になってカンファレンスや勉強会への参加・登壇を活発におこなうようになったことで、頷く点が多かったです。
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </section>
+
+ <section id="section--sessions-thoughts--conference">
+ <h3><a href="#section--sessions-thoughts--conference">カンファレンス</a></h3>
+ <p>
+ ※セッションの題名と発表者名は、<a href="https://fortee.jp/phpconfukuoka-2023/proposal/accepted">カンファレンスの fortee ページ</a>から引用。
+ </p>
+
+ <ul>
+ <li>
+ <a href="https://fortee.jp/phpconfukuoka-2023/proposal/df5f06e8-900e-4e71-94d7-d0c3cc57a0ac">育成力 - エンジニアの才能を引き出す環境とチューターの立ち回り - (岡嵜 雄平 さん)</a>
+ <ul>
+ <li>
+ ちょうど弊チームに新規メンバがジョインしたばかりで、オンボーディングプロセスについて考えていたところの発表でした。 すぐにすべてを取り入れるというわけにはいきませんが、弊社での新人育成プロセスの改善につながるヒントをいくつか得られたと思います。
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ オブジェクト指向は本当に必要か? (たなかひさてる さん、こいほげ さん)
+ <ul>
+ <li>
+ ※当日 D ホールでおこなわれたアンカンファレンスセッションのため、正式タイトル・リンクなし
+ </li>
+
+ <li>
+ 私自身、「オブジェクト指向」については色々と言いたいことがあるのですが、だいたいツイートしたこれとこれです。
+ <ul>
+ <li>
+ 「オブジェクト指向の話は、パラダイムの異なる複数の言語に触れているかどうかで見え方がまったく異なる印象がある。OOPはどうでもいいです (※個人の感想です)」 (<a href="https://twitter.com/nsfisis/status/1672502935983656960">Twitter のツイートへのリンク</a>)
+ </li>
+
+ <li>
+ 「OOPは現代の言語で考える意味はほぼない古いパラダイムだよという立場ですが、OOPについてあまり大っぴらに話してると色んなところから刺されそうなんですよね (Twitterは大っぴらじゃないんですか?)」 (<a href="https://twitter.com/nsfisis/status/1672504892244787201">Twitter のツイートへのリンク</a>)
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ <a href="https://fortee.jp/phpconfukuoka-2023/proposal/ae71f3a7-4c3c-4c87-8816-8426bcc8d325">その説明、コードコメントに書く?コミットメッセージに書く?プルリクエストに書く? (おかしょい/岡田正平 さん)</a>
+ <ul>
+ <li>
+ Twitter にもツイートしましたが、完全に自分の意見と一致していたので、とても共感できました。 今後は社内のコードレビュー時に、こちらの資料を貼りつけることにします。
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </section>
+ </section>
+
+ <section id="section--outro">
+ <h2><a href="#section--outro">おわりに</a></h2>
+ <p>
+ 居住地域から離れた場所への遠征参加は初めてだったが、大変楽しい (しかも勉強にもなる!) 体験だった。 受け取った「熱」が冷める前に、自らの手を動かしていきたい。
+ </p>
+ </section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/vhosts/blog/public/posts/index.html b/vhosts/blog/public/posts/index.html
new file mode 100644
index 00000000..acd16a6c
--- /dev/null
+++ b/vhosts/blog/public/posts/index.html
@@ -0,0 +1,389 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="投稿した記事の一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>投稿一覧 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css?h=37fff6a2f0eef473abde58e55f28ea69">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <ul>
+ <li>
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </li>
+ <li>
+ <a href="/about/">About</a>
+ </li>
+ <li>
+ <a href="/posts/">Posts</a>
+ </li>
+ <li>
+ <a href="/slides/">Slides</a>
+ </li>
+ <li>
+ <a href="/tags/">Tags</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>投稿一覧</h1>
+ </header>
+ <article class="post-entry">
+ <a href="/posts/2023-06-25/phpconfuk-2023-report/">
+ <header class="entry-header">
+ <h2>PHP カンファレンス福岡 2023 参加レポ</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 2023-06-24 に開催された、PHP カンファレンス福岡に参加した。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2023-06-25">2023-06-25</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2023-04-04/phperkaigi-2023-report/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2023 参加レポ</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 2023-03-23 から 2023-03-25 にかけて開催された、PHPerKaigi 2023 に参加した。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2023-04-04">2023-04-04</time> 投稿、<time datetime="2023-06-28">2023-06-28</time> 更新
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2023-04-01/implementation-of-minimal-png-image-encoder/">
+ <header class="entry-header">
+ <h2>PNG 画像の最小構成エンコーダを実装する</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PNG 画像として valid な範囲で最大限手抜きしたエンコーダを書く。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2023-04-01">2023-04-01</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2023-03-10/rewrite-this-blog-generator/">
+ <header class="entry-header">
+ <h2>このブログのジェネレータを書き直した</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ このブログのジェネレータを書き直したので、やったことを書き記しておく。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2023-03-10">2023-03-10</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2023: ボツになったトークン問題 その 3</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、ボツになった問題を公開する (その 3)。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2023-01-10">2023-01-10</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2023: ボツになったトークン問題 その 2</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、ボツになった問題を公開する (その 2)。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2022-11-19">2022-11-19</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2022-10-28/setup-server-for-this-site/">
+ <header class="entry-header">
+ <h2>【備忘録】 このサイト用の VPS をセットアップしたときのメモ</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ GitHub Pages でホストしていたこのサイトを VPS へ移行したので、そのときにやったことのメモ。99 % 自分用。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2022-10-28">2022-10-28</time> 投稿、<time datetime="2023-08-30">2023-08-30</time> 更新
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2023: ボツになったトークン問題 その 1</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、ボツになった問題を公開する (その 1)。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2022-10-23">2022-10-23</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/">
+ <header class="entry-header">
+ <h2>【PHP】 fizzbuzz を書く。1行あたり2文字で。</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2022-09-28">2022-09-28</time> 投稿、<time datetime="2022-09-29">2022-09-29</time> 更新
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2022-08-31/support-for-communty-is-employee-benefits/">
+ <header class="entry-header">
+ <h2>弊社の PHP Foundation への寄付に寄せて</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 先日、私の勤めるデジタルサーカス株式会社が、PHP Foundation へ寄付をおこないました。 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2022-08-31">2022-08-31</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2022-08-27/php-conference-okinawa-code-golf/">
+ <header class="entry-header">
+ <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2022-08-27">2022-08-27</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2022-05-01/phperkaigi-2022/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2022</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2022-05-01">2022-05-01</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/">
+ <header class="entry-header">
+ <h2>term-banner: ターミナルにバナーを表示するツールを書いた</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ ターミナルに任意の文字のバナーを表示するためのツールを Go で書いた。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2022-04-24">2022-04-24</time> 投稿、<time datetime="2022-04-27">2022-04-27</time> 更新
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2022-04-09/phperkaigi-2022-tokens/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2022 トークン問題の解説</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2022-04-09">2022-04-09</time> 投稿、<time datetime="2022-04-16">2022-04-16</time> 更新
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/">
+ <header class="entry-header">
+ <h2>【C++】 属性構文の属性名にはキーワードが使える</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ C++ の属性構文の属性名には、キーワードが使える。ネタ記事。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2021-10-02">2021-10-02</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/python-unbound-local-error/">
+ <header class="entry-header">
+ <h2>【Python】 クロージャとUnboundLocalError: local variable &apos;x&apos; referenced before assignment</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Python における UnboundLocalError の理由と対処法。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2021-10-02">2021-10-02</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/ruby-detect-running-implementation/">
+ <header class="entry-header">
+ <h2>【Ruby】 自身を実行している処理系の種類を判定する</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Ruby には複数の実装があるが、自身を実行している処理系の種類をスクリプト上からどのように判定すればよいだろうか。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2021-10-02">2021-10-02</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/ruby-then-keyword-and-case-in/">
+ <header class="entry-header">
+ <h2>【Ruby】 then キーワードと case in</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Ruby 3.0 で追加される case in 構文と、then キーワードについて。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2021-10-02">2021-10-02</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/rust-where-are-primitive-types-from/">
+ <header class="entry-header">
+ <h2>Rust のプリミティブ型はどこからやって来るか</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Rust のプリミティブ型は予約語ではなく普通の識別子である。どのようにこれが名前解決されるのかを調べた。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2021-10-02">2021-10-02</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/">
+ <header class="entry-header">
+ <h2>【Vim】 autocmd events の BufWrite/BufWritePre の違い</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、違いはないことがわかった。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2021-10-02">2021-10-02</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/vim-swap-order-of-selected-lines/">
+ <header class="entry-header">
+ <h2>Vimで選択した行の順番を入れ替える</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Vim で選択した行の順番を入れ替える方法。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2021-10-02">2021-10-02</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2021-03-30/phperkaigi-2021/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2021</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2021-03-30">2021-03-30</time> 投稿
+ </footer>
+ </a>
+ </article>
+ <article class="post-entry">
+ <a href="/posts/2021-03-05/my-first-post/">
+ <header class="entry-header">
+ <h2>My First Post</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ これはテスト投稿です。これはテスト投稿です。これはテスト投稿です。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ <time datetime="2021-03-05">2021-03-05</time> 投稿
+ </footer>
+ </a>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>