diff options
| author | nsfisis <nsfisis@gmail.com> | 2023-03-19 00:47:11 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2023-03-19 00:47:11 +0900 |
| commit | 88b66f82aae2d7784002b07bfc7877932da3ec94 (patch) | |
| tree | 4950a8f9f740715f2c56383309edab97df37a2f5 | |
| parent | 0e5fff11e9a455273dad77fc26796af03ddf08d3 (diff) | |
| download | blog.nsfisis.dev-88b66f82aae2d7784002b07bfc7877932da3ec94.tar.gz blog.nsfisis.dev-88b66f82aae2d7784002b07bfc7877932da3ec94.tar.zst blog.nsfisis.dev-88b66f82aae2d7784002b07bfc7877932da3ec94.zip | |
fix(content): fix XML notations
64 files changed, 4900 insertions, 3552 deletions
diff --git a/content/posts/2021-03-30/phperkaigi-2021.xml b/content/posts/2021-03-30/phperkaigi-2021.xml index 3cfbb0b..745db4b 100644 --- a/content/posts/2021-03-30/phperkaigi-2021.xml +++ b/content/posts/2021-03-30/phperkaigi-2021.xml @@ -19,456 +19,760 @@ </info> <section xml:id="_phperkaigi_2021_参加レポ"> <title>PHPerKaigi 2021 参加レポ</title> - <simpara>2021-03-26 から 2021-03-28 - にかけて開催された、 <link xl:href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</link> - に一般参加者として参加した。 - 弊社 <link xl:href="https://www.dgcircus.com/">デジタルサーカス株式会社</link> - (今年1月から勤務) - はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</simpara> - <simpara>このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。</simpara> - <simpara>発表はトラック A、B に分かれていたのだが、今回はすべて A - トラックを視聴している (切り替えるのが面倒だっただけ)。</simpara> -<section xml:id="_凡例"> - <title>凡例</title> - <blockquote> - <simpara>発表・スライドのメモ (引用ではない)</simpara> - </blockquote> - <simpara>感想など</simpara> -</section> -<section xml:id="_day_0_前夜祭_20210327"> - <title>Day 0 前夜祭 (2021/03/27)</title> - <section xml:id="_1730_a"> - <title>17:30 [A]</title> - <simpara>PHP で AWS Lambda</simpara> - <blockquote> - <simpara>Rails のプロジェクトを PHPer のメンバのみでメンテ →他のメンバもわかる - PHP にリプレースを検討</simpara> - <itemizedlist> - <listitem>サーバレス</listitem> - <listitem>サーバ・インフラの管理が不要</listitem> - <listitem>アプリケーションコードの知識だけで保守可能</listitem> - </itemizedlist> - <simpara>ゼロベースで作れる案件が (Railsの件とは別に) - あるため、そちらで試験的に導入?</simpara> - <simpara>AWSの学習 AWS のドキュメント DevelopersIO</simpara> - <simpara>AWS Lambda のカスタムランタイムで PHP を動かす</simpara> - <simpara>サーバのセットアップや維持管理を気にしなくて良い サーバーレスで PHP - を動かすツールがすでにある サーバーレス構築はすんなり</simpara> -<simpara>今は Laravel がルーティングしている Laravel Livewire を Lambda -に載せられないか? デプロイ方法は? バッチ処理は? (Lambda は -15分の制限)</simpara> -<simpara>Lambda でコンテナイメージがサポートされるように</simpara> -<simpara>抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる</simpara> -</blockquote> -<simpara>AWS Lambda のような Function as a Service -はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に -web サービスを作る具体的なイメージがまだ見えない (注: すべて for me -として書いている)。</simpara> -<simpara>PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。</simpara> -<simpara>勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + - Laravel などでは動かなさそう) - だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。</simpara> -</section> -<section xml:id="_1810_a"> - <title>18:10 [A]</title> - <simpara>大規模サイトの SEO</simpara> - <blockquote> - <simpara>大規模サイト (100万ページ以上) Google の基準</simpara> - <simpara>クロールバジェットを意識したSEO</simpara> - <simpara>大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト - (10,000以上) でコンテンツが目まぐるしく変更される - これを満たさないなら、クロールバジェットを考えなくてもいい</simpara> - <simpara>サーチコンソール 「カバレッジ」の「除外」 - 多すぎるのは問題→クロールバジェットを浪費している</simpara> -<itemizedlist> - <listitem>クエリの順番を決める</listitem> - <listitem>空の値のルールを決めておく</listitem> - <listitem>リダイレクトすればインデックスはうまくいく</listitem> - <listitem>リンクが存在する限りクロールはされる</listitem> -</itemizedlist> -<simpara>リニューアル前のURL</simpara> -<simpara>インデックスは移行される -リンクのURLが存在する限り、別のURLとしてクロールされる -リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い -リニューアルで無視されるようになったパラメータも注意</simpara> -<simpara>robotes.txt で拒否しているのにクロールされる 一時的に拒否を外して 404 や -301 を読ませる 内部リンクを確認する JS でのリンクに書き換え</simpara> -<simpara>クエリパラメータからURLのパスに <literal>/tokyo?area=HOGE</literal> → <literal>/tokyo/HOGE</literal></simpara> -<simpara>URL 設計だいじ</simpara> -</blockquote> -<simpara>SEO (Search Engine Optimization) -は大して知らないので新鮮な話が多かった。その分語れることも少ない……。</simpara> -</section> -<section xml:id="_1850_a"> - <title>18:50 [A]</title> - <blockquote> - <simpara>知覚可能 操作可能 理解可能 堅牢 ちゃんとしたHTMLを書く - (閉じタグ・入れ子構造など)</simpara> - <itemizedlist> - <listitem>標準の HTML を適切に使う</listitem> - <listitem>WAI-ARIA</listitem> - <listitem>キーボードフレンドリー</listitem> - <listitem>マシンフレンドリー</listitem> - <listitem>SEOフレンドリー</listitem> - </itemizedlist> - <simpara>button タグ →キーボード h1 タグ →スクリーンリーダー・クローラ a タグ</simpara> - <simpara>WAI-ARIA HTML では表現できないセマンティクスを追加する</simpara> - <itemizedlist> - <listitem> - ロール - <itemizedlist> - <listitem>何をするのか?</listitem> - <listitem>ユーザーアクションによって変化しない</listitem> - </itemizedlist> - </listitem> - <listitem> - プロパティ - <itemizedlist> - <listitem>関連づけられたデータ</listitem> - </itemizedlist> - </listitem> - <listitem> - ステート - <itemizedlist> - <listitem>現在の状態</listitem> - </itemizedlist> - </listitem> - </itemizedlist> - <simpara>まずは標準の HTML 要素で解決する 何でもかんでも WAI-ARIA - を使えばいいというものではない</simpara> -<simpara>マウスホバーでツールチップが出てくるが、キーボード操作では出てこない</simpara> -<simpara>VoiceOver</simpara> -<simpara>全ての属性を使う必要はない -あくまでアクセシビリティを上げるための方法の一つにすぎない</simpara> -</blockquote> -<simpara>つい最近 WAI-ARIA -についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) -いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。</simpara> -</section> -<section xml:id="_1930_a"> - <title>19:30 [A]</title> - <simpara>PHP で FUSE</simpara> - <simpara>個人的に楽しみだった発表。</simpara> - <blockquote> - <simpara>VFS (virtual filesystem) vs 具体的なファイルシステム</simpara> - <simpara>最適な実装方法は状況により異なる</simpara> - <simpara>アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS</simpara> - <simpara>カーネルのプログラムを作るのは難しい - * 権限がデカすぎる - * システム全体がクラッシュ - * セキュリティリスク - * 開発サイクルを回しづらい - * ネイティブコードにコンパイルされる言語である必要がある</simpara> - <simpara>Filesystem in USEr space (FUSE)</simpara> - <itemizedlist> - <listitem>特定の C の関数を呼ぶことで filesystem が作れる</listitem> - <listitem>FFI を持つ言語なら FUSE が使える</listitem> - </itemizedlist> - <simpara>SSHFS / s3fs / Docker Desktop</simpara> - <simpara>Linux 以外でも使える</simpara> - <itemizedlist> - <listitem>dokany (on Windows)</listitem> - <listitem>osxfuse</listitem> - </itemizedlist> - <simpara>VFS: システムコールが呼ばれると、ファイルシステムによってコール FUSE: - カーネル空間からユーザ空間へ通信</simpara> -<simpara>高レベルなラッパで型をつける</simpara> -<simpara>PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)</simpara> -<itemizedlist> - <listitem>grep できる</listitem> - <listitem>sed できる</listitem> - <listitem>編集できる</listitem> -</itemizedlist> -</blockquote> -<simpara>期待通りの興味深い発表だった。FUSE -自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。 -この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ -(ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。</simpara> -</section> -</section> -<section xml:id="_day_1_20210327"> - <title>Day 1 (2021/03/27)</title> - <section xml:id="_1050_a"> - <title>10:50 [A]</title> - <simpara>ATDD</simpara> - <blockquote> - <itemizedlist> - <listitem>ユーザーストーリー</listitem> - <listitem>ユニットテスト</listitem> - <listitem>CI/CD</listitem> - </itemizedlist> - <simpara>ユーザストーリーの受け入れ条件が曖昧になりがち - デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている</simpara> - <simpara>Q2の強化 アジャイルテストの4象限</simpara> - <simpara>技術面/ビジネス面 - 開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)</simpara> - <itemizedlist> - <listitem> - Q1: 技術面 & チーム支援 - <itemizedlist> - <listitem>TDD</listitem> - <listitem>ユニットテストなど</listitem> - </itemizedlist> - </listitem> - <listitem> - Q2: ビジネス面 & チーム支援 - <itemizedlist> - <listitem>ATDD</listitem> - <listitem>ビジネス面の受け入れテストで駆動する</listitem> - </itemizedlist> - </listitem> - </itemizedlist> - <simpara>Agile Alliance ユーザストーリーのスキルレベルを高める</simpara> - <simpara>テストピラミッド</simpara> - <itemizedlist> - <listitem>UI Tests</listitem> - <listitem>Service Tests</listitem> - <listitem>Unit Tests</listitem> - <listitem>異なる粒度のテストを書く</listitem> - <listitem> - 高レベルになるほど、持つべきテストは少なくなる - <itemizedlist> - <listitem>ピラミッド型になる</listitem> - </itemizedlist> - </listitem> - </itemizedlist> - <simpara>高レベルテストが多すぎる→アイスクリームコーン アンチパターン</simpara> - <simpara>ATDD (Acceptance TDD) API経由・UI経由での高レベルテスト E2E test</simpara> - <simpara>ストーリ受け入れテスト</simpara> - <simpara>入れ子のフィードバックループ ATDD(外側) と TDD(内側)</simpara> - <simpara>外部品質・内部品質</simpara> - <simpara>バーティカルスライスのデリバリー</simpara> - <itemizedlist> - <listitem>cucumber</listitem> - <listitem>gauge</listitem> - <listitem>behat</listitem> - </itemizedlist> - <simpara>ユビキタス言語 手動テストもspecに書く 自動化は可能だがコスパが悪い - 失敗することがわかっているテスト(レッドテスト)はCIから外す - 失敗時の原因究明が難しい 饒舌なエラーメッセージ 状況のスナップショット</simpara> -<simpara>Continuous Testing</simpara> -</blockquote> -<simpara>User Acceptance Test (UAT) -くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。 -高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。</simpara> -</section> -<section xml:id="_1150_a"> - <title>11:50 [A]</title> - <simpara>型解析を用いたリファクタリング</simpara> - <simpara>型のある世界で生きてきた身として大いに楽しみにしていた発表。</simpara> - <blockquote> - <itemizedlist> - <listitem>PHPStan</listitem> - <listitem>Phan</listitem> - <listitem>Psalm</listitem> - </itemizedlist> - <simpara>autoload も認識できる bootstrapFiles</simpara> - <simpara>編集箇所と利用箇所を CI でチェック ルールレベルを徐々に引き上げていく - 警告が多すぎると見落としてしまう・無視されやすくなる</simpara> - <simpara>型がついていないことによるエラーが多い</simpara> - <simpara>型よりも詳細な検査 <literal>Util_Assert::min</literal></simpara> - <simpara>SQL を静的解析 placeholder の型付け</simpara> - <simpara>警告レベルを低いレベルから導入 タイプヒントを積極的に書いていく PHPStan - の拡張を追加する</simpara> -</blockquote> -<simpara>昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。 -今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で -Ruby の typeprof には注目している。</simpara> -</section> -<section xml:id="_1230_a"> - <title>12:30 [A]</title> - <simpara>昼食をとっていた。事前に何か食料を買っておくべきだった。</simpara> -</section> -<section xml:id="_1310_a"> - <title>13:10 [A]</title> - <simpara>Documentation as Code</simpara> - <simpara>この発表も以前から非常に楽しみにしていた。</simpara> - <blockquote> - <simpara>開発開始までのオーバーヘッド 新規にチームにジョイン - 担当範囲外の機能を理解 オンボーディングのコスト</simpara> - <simpara>PHPerKaigi 2020 で発表あり</simpara> - <simpara>継続的にシステムの理解を助けるドキュメント</simpara> - <simpara>継続的ドキュメンテーション システムとドキュメントの乖離</simpara> - <simpara>書いてあることが間違っている・足りない * 徐々にずれていく * - システムの更新タイミングとドキュメントの更新タイミングに差がある</simpara> -<simpara>システムとドキュメントは対応関係がある * 間違ったドキュメント * -存在しないドキュメント</simpara> -<simpara>システムとドキュメントの乖離を定量化する 継続的に -システムの更新に近いタイミングで ドキュメントを更新し続ける</simpara> -<simpara>Documentation as Code</simpara> -<simpara>コードと同じツールでドキュメントを書く * issue tracker * vcs * plain -text markup * automation</simpara> -<simpara>開発者 システム ドキュメント 構造化データ ソフトウェア</simpara> -<simpara>システムから構造化データを抽出する PHPDoc OpenAPI</simpara> -<simpara>ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する</simpara> -<simpara>ビューの単位でドキュメントに</simpara> -<simpara>スタックトレースからのドキュメント生成</simpara> -</blockquote> -<simpara>ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な -(乖離しない) -情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。</simpara> -</section> -<section xml:id="_1410_a"> - <title>14:10 [A]</title> - <simpara>cookie による session 管理</simpara> - <simpara>全体的に基本的な話だったので特に触れない。Cookie - やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。</simpara> -</section> -<section xml:id="_1450_a"> - <title>14:50 [A]</title> - <simpara>PHP のエラーと例外</simpara> - <blockquote> - <simpara>エラー PHPエンジンがエラーを通知する 例外 プログラムが投げる</simpara> - <simpara>PHP7-8とエラー</simpara> - <simpara>PHPエンジンのエラーの一部が に変換されるようになった → try-catch - で捕捉できる</simpara> - <simpara>は例外とは異なる</simpara> - <simpara>PHP8 でエラーレベルの引き上げ</simpara> - <itemizedlist> - <listitem> - 捕捉すべきもの - <itemizedlist> - <listitem>recoverable</listitem> - </itemizedlist> - </listitem> - <listitem> - 捕捉すべきでないもの - <itemizedlist> - <listitem>unrecoverable</listitem> - <listitem>開発時に対処できるもの</listitem> - </itemizedlist> - </listitem> - </itemizedlist> - <simpara>例外 * 捕捉して事後処理 * 捕捉せず(or 捕捉した上で)さらに上に是非を問う</simpara> - <simpara>開発段階で例外を把握し、ハンドリングを考えておく</simpara> - <simpara>と</simpara> - <simpara>はキャッチすべきでない</simpara> - <itemizedlist> - <listitem> - <simpara></simpara> - <itemizedlist> - <listitem>本番で起きてはいけない</listitem> - </itemizedlist> - </listitem> - <listitem> - <simpara></simpara> - <itemizedlist> - <listitem>本番で起きてはいけない →生じないのだから捕捉もしない</listitem> - </itemizedlist> - </listitem> - <listitem> - <simpara></simpara> - <itemizedlist> - <listitem>起こるかもしれないので本番環境でも考慮する</listitem> - </itemizedlist> - </listitem> - </itemizedlist> - <simpara>捕捉して対応するのではなく、未然に防ぐ</simpara> - <simpara>独自例外を使う を投げてしまうと、 catch ()せざるを得ない →catch - 範囲が広すぎる</simpara> -<simpara>SPL の例外を使う</simpara> -<simpara>例外翻訳 -上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する -下位レイヤの知識に依存させない</simpara> -<simpara>@throws 捕捉してほしい例外を書き連ねておく</simpara> -<simpara>呼び出しもとに負わせたい責任</simpara> -</blockquote> -<simpara>PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で -PHP を書き始めてから 4ヶ月ほどになる)。</simpara> -<simpara>個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell -などのエラーを「値として」扱う言語だと思っている。try-catch -は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は -C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる -(C のそれはまともな型付けではない。念のため)。</simpara> -<simpara>PHP -のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。</simpara> -</section> -<section xml:id="_1530_a"> - <title>15:30 [A]</title> - <simpara>Laravel のメール認証</simpara> - <simpara>Laravel - の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。</simpara> -</section> -<section xml:id="_1610_a"> - <title>16:10 [A]</title> - <simpara>gRPC</simpara> - <blockquote> - <simpara>Unary RPCs Server streaming RPCs Client streaming RPCs Bidirectional - streaming RPCs</simpara> - <simpara>Protobuf</simpara> - <simpara>実装とAPIが乖離しにくい 自動生成 複数言語でも相互に使える</simpara> - <simpara>マイクロサービスのサービス通信 スマホアプリ ゲームサーバ</simpara> - <simpara>PHP では?</simpara> - <simpara>PHP ではストリーミングが難しい リクエストごとにプロセスが使い捨て</simpara> - <simpara>PHP ではgRPCのクライアントしか対応していない</simpara> - <simpara>gRPC-Web ブラウザで扱うためのJSライブラリ+プロトコル</simpara> - <simpara>HTTP/1.1 でも使える Unary RPC と Server streaming RPC のみ</simpara> - <simpara>Envoy Nginx などで相互に gRPC と gRPC-Web で変換</simpara> - <simpara>Amp イベント駆動な並行処理のフレームワーク</simpara> - <simpara>HTTP/2 対応</simpara> - <simpara>C#のgRPC-Webが楽</simpara> -</blockquote> -<simpara>(発表の中でもまさに同じことをおっしゃっていたが) PHP -以外の方が向いているだろう、というのが第一の感想である。gRPC -はそれ自体というよりも Protobuf -というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。</simpara> -</section> -<section xml:id="_1650_a"> - <title>16:50 [A]</title> - <simpara>アーキテクチャテスト</simpara> - <blockquote> - <simpara>Independent Core Layer Pattern</simpara> - <simpara>開発初期のアーキテクチャが崩れる - アーキテクチャ観点のコードレビューができない</simpara> - <simpara>どこにクラスを置けばよいか? ドキュメントがない</simpara> - <simpara>アーキテクチャ設計に関する知識が属人化・暗黙知化</simpara> - <simpara>ガイドライン * 最初にルールを決めるのは簡単 * - ルール通り作り始めるのも簡単 * - →維持するのが難しい、人が決めたものゆえ壊れやすい</simpara> -<simpara>PHP の特性 * クラスは public * 可視性の制御が public / protected / -private のみ * 依存関係の制御が困難</simpara> -<simpara>アーキテクチャテスト -クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する</simpara> -<itemizedlist> - <listitem>deptrac</listitem> - <listitem>phpat</listitem> -</itemizedlist> -<simpara>Independent Core Layer Pattern</simpara> -<simpara>アーキテクチャテストの失敗 * 実装誤り * or アーキテクチャが適切でない * -開発の過程でフィードバックしていく</simpara> -<simpara>モジュラーモノリス→マイクロサービスへ</simpara> -</blockquote> -</section> -</section> -<section xml:id="_day_2_20210328"> - <title>Day 2 (2021/03/28)</title> - <simpara>冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。</simpara> - <simpara>残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。</simpara> -</section> -<section xml:id="_全体の感想"> - <title>全体の感想</title> - <simpara>Day 2 - にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも - (特に初参加者として) 嬉しいポイントだった。</simpara> -<simpara>今回、雑談/登壇者への質問等向けに Discord -サーバもあったのだが、こちらは参加こそしたものの ROM -のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord -表示に -1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった -(さらにいうと Zoom -でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。</simpara> -<simpara>1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord -しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 -まあ初カンファレンスだし、とお茶を濁しておこう。</simpara> -<simpara>さて、カンファレンスで一つ気になったことがある。それは、Discord -という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord -の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord -があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。</simpara> -<simpara><hr/></simpara> -<simpara>最後になりましたが、毎年の PHPerKaigi -開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました! -(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)</simpara> -<simpara>ではまた来年。</simpara> -</section> -</section> + <simpara> + 2021-03-26 から 2021-03-28 + にかけて開催された、 <link xl:href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</link> + に一般参加者として参加した。 + 弊社 <link xl:href="https://www.dgcircus.com/">デジタルサーカス株式会社</link> + (今年1月から勤務) + はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。 + </simpara> + <simpara> + このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。 + </simpara> + <simpara> + 発表はトラック A、B に分かれていたのだが、今回はすべて A + トラックを視聴している (切り替えるのが面倒だっただけ)。 + </simpara> + <section xml:id="_凡例"> + <title>凡例</title> + <blockquote> + <simpara> + 発表・スライドのメモ (引用ではない) + </simpara> + </blockquote> + <simpara> + 感想など + </simpara> + </section> + <section xml:id="_day_0_前夜祭_20210327"> + <title>Day 0 前夜祭 (2021/03/27)</title> + <section xml:id="_1730_a"> + <title>17:30 [A]</title> + <simpara> + PHP で AWS Lambda + </simpara> + <blockquote> + <simpara> + Rails のプロジェクトを PHPer のメンバのみでメンテ →他のメンバもわかる + PHP にリプレースを検討 + </simpara> + <itemizedlist> + <listitem>サーバレス</listitem> + <listitem>サーバ・インフラの管理が不要</listitem> + <listitem>アプリケーションコードの知識だけで保守可能</listitem> + </itemizedlist> + <simpara> + ゼロベースで作れる案件が (Railsの件とは別に) + あるため、そちらで試験的に導入? + </simpara> + <simpara> + AWSの学習 AWS のドキュメント DevelopersIO + </simpara> + <simpara> + AWS Lambda のカスタムランタイムで PHP を動かす + </simpara> + <simpara> + サーバのセットアップや維持管理を気にしなくて良い サーバーレスで PHP + を動かすツールがすでにある サーバーレス構築はすんなり + </simpara> + <simpara> + 今は Laravel がルーティングしている Laravel Livewire を Lambda + に載せられないか? デプロイ方法は? バッチ処理は? (Lambda は + 15分の制限) + </simpara> + <simpara> + Lambda でコンテナイメージがサポートされるように + </simpara> + <simpara> + 抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる + </simpara> + </blockquote> + <simpara> + AWS Lambda のような Function as a Service + はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に + web サービスを作る具体的なイメージがまだ見えない (注: すべて for me + として書いている)。 + </simpara> + <simpara> + PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。 + </simpara> + <simpara> + 勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + + Laravel などでは動かなさそう) + だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。 + </simpara> + </section> + <section xml:id="_1810_a"> + <title>18:10 [A]</title> + <simpara> + 大規模サイトの SEO + </simpara> + <blockquote> + <simpara> + 大規模サイト (100万ページ以上) Google の基準 + </simpara> + <simpara> + クロールバジェットを意識したSEO + </simpara> + <simpara> + 大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト + (10,000以上) でコンテンツが目まぐるしく変更される + これを満たさないなら、クロールバジェットを考えなくてもいい + </simpara> + <simpara> + サーチコンソール 「カバレッジ」の「除外」 + 多すぎるのは問題→クロールバジェットを浪費している + </simpara> + <itemizedlist> + <listitem>クエリの順番を決める</listitem> + <listitem>空の値のルールを決めておく</listitem> + <listitem>リダイレクトすればインデックスはうまくいく</listitem> + <listitem>リンクが存在する限りクロールはされる</listitem> + </itemizedlist> + <simpara> + リニューアル前のURL + </simpara> + <simpara> + インデックスは移行される + リンクのURLが存在する限り、別のURLとしてクロールされる + リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い + リニューアルで無視されるようになったパラメータも注意 + </simpara> + <simpara> + robotes.txt で拒否しているのにクロールされる 一時的に拒否を外して 404 や + 301 を読ませる 内部リンクを確認する JS でのリンクに書き換え + </simpara> + <simpara> + クエリパラメータからURLのパスに <literal>/tokyo?area=HOGE</literal> → <literal>/tokyo/HOGE</literal> + </simpara> + <simpara> + URL 設計だいじ + </simpara> + </blockquote> + <simpara> + SEO (Search Engine Optimization) + は大して知らないので新鮮な話が多かった。その分語れることも少ない……。 + </simpara> + </section> + <section xml:id="_1850_a"> + <title>18:50 [A]</title> + <blockquote> + <simpara> + 知覚可能 操作可能 理解可能 堅牢 ちゃんとしたHTMLを書く + (閉じタグ・入れ子構造など) + </simpara> + <itemizedlist> + <listitem>標準の HTML を適切に使う</listitem> + <listitem>WAI-ARIA</listitem> + <listitem>キーボードフレンドリー</listitem> + <listitem>マシンフレンドリー</listitem> + <listitem>SEOフレンドリー</listitem> + </itemizedlist> + <simpara> + button タグ →キーボード h1 タグ →スクリーンリーダー・クローラ a タグ + </simpara> + <simpara> + WAI-ARIA HTML では表現できないセマンティクスを追加する + </simpara> + <itemizedlist> + <listitem> + ロール + <itemizedlist> + <listitem>何をするのか?</listitem> + <listitem>ユーザーアクションによって変化しない</listitem> + </itemizedlist> + </listitem> + <listitem> + プロパティ + <itemizedlist> + <listitem>関連づけられたデータ</listitem> + </itemizedlist> + </listitem> + <listitem> + ステート + <itemizedlist> + <listitem>現在の状態</listitem> + </itemizedlist> + </listitem> + </itemizedlist> + <simpara> + まずは標準の HTML 要素で解決する 何でもかんでも WAI-ARIA + を使えばいいというものではない + </simpara> + <simpara> + マウスホバーでツールチップが出てくるが、キーボード操作では出てこない + </simpara> + <simpara> + VoiceOver + </simpara> + <simpara> + 全ての属性を使う必要はない + あくまでアクセシビリティを上げるための方法の一つにすぎない + </simpara> + </blockquote> + <simpara> + つい最近 WAI-ARIA + についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) + いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。 + </simpara> + </section> + <section xml:id="_1930_a"> + <title>19:30 [A]</title> + <simpara> + PHP で FUSE + </simpara> + <simpara> + 個人的に楽しみだった発表。 + </simpara> + <blockquote> + <simpara> + VFS (virtual filesystem) vs 具体的なファイルシステム + </simpara> + <simpara> + 最適な実装方法は状況により異なる + </simpara> + <simpara> + アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS + </simpara> + <simpara> + カーネルのプログラムを作るのは難しい + * 権限がデカすぎる + * システム全体がクラッシュ + * セキュリティリスク + * 開発サイクルを回しづらい + * ネイティブコードにコンパイルされる言語である必要がある + </simpara> + <simpara> + Filesystem in USEr space (FUSE) + </simpara> + <itemizedlist> + <listitem>特定の C の関数を呼ぶことで filesystem が作れる</listitem> + <listitem>FFI を持つ言語なら FUSE が使える</listitem> + </itemizedlist> + <simpara> + SSHFS / s3fs / Docker Desktop + </simpara> + <simpara> + Linux 以外でも使える + </simpara> + <itemizedlist> + <listitem>dokany (on Windows)</listitem> + <listitem>osxfuse</listitem> + </itemizedlist> + <simpara> + VFS: システムコールが呼ばれると、ファイルシステムによってコール FUSE: + カーネル空間からユーザ空間へ通信 + </simpara> + <simpara> + 高レベルなラッパで型をつける + </simpara> + <simpara> + PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など) + </simpara> + <itemizedlist> + <listitem>grep できる</listitem> + <listitem>sed できる</listitem> + <listitem>編集できる</listitem> + </itemizedlist> + </blockquote> + <simpara> + 期待通りの興味深い発表だった。FUSE + 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。 + この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ + (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。 + </simpara> + </section> + </section> + <section xml:id="_day_1_20210327"> + <title>Day 1 (2021/03/27)</title> + <section xml:id="_1050_a"> + <title>10:50 [A]</title> + <simpara> + ATDD + </simpara> + <blockquote> + <itemizedlist> + <listitem>ユーザーストーリー</listitem> + <listitem>ユニットテスト</listitem> + <listitem>CI/CD</listitem> + </itemizedlist> + <simpara> + ユーザストーリーの受け入れ条件が曖昧になりがち + デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている + </simpara> + <simpara> + Q2の強化 アジャイルテストの4象限 + </simpara> + <simpara> + 技術面/ビジネス面 + 開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後) + </simpara> + <itemizedlist> + <listitem> + Q1: 技術面 & チーム支援 + <itemizedlist> + <listitem>TDD</listitem> + <listitem>ユニットテストなど</listitem> + </itemizedlist> + </listitem> + <listitem> + Q2: ビジネス面 & チーム支援 + <itemizedlist> + <listitem>ATDD</listitem> + <listitem>ビジネス面の受け入れテストで駆動する</listitem> + </itemizedlist> + </listitem> + </itemizedlist> + <simpara> + Agile Alliance ユーザストーリーのスキルレベルを高める + </simpara> + <simpara> + テストピラミッド + </simpara> + <itemizedlist> + <listitem>UI Tests</listitem> + <listitem>Service Tests</listitem> + <listitem>Unit Tests</listitem> + <listitem>異なる粒度のテストを書く</listitem> + <listitem> + 高レベルになるほど、持つべきテストは少なくなる + <itemizedlist> + <listitem>ピラミッド型になる</listitem> + </itemizedlist> + </listitem> + </itemizedlist> + <simpara> + 高レベルテストが多すぎる→アイスクリームコーン アンチパターン + </simpara> + <simpara> + ATDD (Acceptance TDD) API経由・UI経由での高レベルテスト E2E test + </simpara> + <simpara> + ストーリ受け入れテスト + </simpara> + <simpara> + 入れ子のフィードバックループ ATDD(外側) と TDD(内側) + </simpara> + <simpara> + 外部品質・内部品質 + </simpara> + <simpara> + バーティカルスライスのデリバリー + </simpara> + <itemizedlist> + <listitem>cucumber</listitem> + <listitem>gauge</listitem> + <listitem>behat</listitem> + </itemizedlist> + <simpara> + ユビキタス言語 手動テストもspecに書く 自動化は可能だがコスパが悪い + 失敗することがわかっているテスト(レッドテスト)はCIから外す + 失敗時の原因究明が難しい 饒舌なエラーメッセージ 状況のスナップショット + </simpara> + <simpara> + Continuous Testing + </simpara> + </blockquote> + <simpara> + User Acceptance Test (UAT) + くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。 + 高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。 + </simpara> + </section> + <section xml:id="_1150_a"> + <title>11:50 [A]</title> + <simpara> + 型解析を用いたリファクタリング + </simpara> + <simpara> + 型のある世界で生きてきた身として大いに楽しみにしていた発表。 + </simpara> + <blockquote> + <itemizedlist> + <listitem>PHPStan</listitem> + <listitem>Phan</listitem> + <listitem>Psalm</listitem> + </itemizedlist> + <simpara> + autoload も認識できる bootstrapFiles + </simpara> + <simpara> + 編集箇所と利用箇所を CI でチェック ルールレベルを徐々に引き上げていく + 警告が多すぎると見落としてしまう・無視されやすくなる + </simpara> + <simpara> + 型がついていないことによるエラーが多い + </simpara> + <simpara> + 型よりも詳細な検査 <literal>Util_Assert::min</literal> + </simpara> + <simpara> + SQL を静的解析 placeholder の型付け + </simpara> + <simpara> + 警告レベルを低いレベルから導入 タイプヒントを積極的に書いていく PHPStan + の拡張を追加する + </simpara> + </blockquote> + <simpara> + 昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。 + 今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で + Ruby の typeprof には注目している。 + </simpara> + </section> + <section xml:id="_1230_a"> + <title>12:30 [A]</title> + <simpara> + 昼食をとっていた。事前に何か食料を買っておくべきだった。 + </simpara> + </section> + <section xml:id="_1310_a"> + <title>13:10 [A]</title> + <simpara> + Documentation as Code + </simpara> + <simpara> + この発表も以前から非常に楽しみにしていた。 + </simpara> + <blockquote> + <simpara> + 開発開始までのオーバーヘッド 新規にチームにジョイン + 担当範囲外の機能を理解 オンボーディングのコスト + </simpara> + <simpara> + PHPerKaigi 2020 で発表あり + </simpara> + <simpara> + 継続的にシステムの理解を助けるドキュメント + </simpara> + <simpara> + 継続的ドキュメンテーション システムとドキュメントの乖離 + </simpara> + <simpara> + 書いてあることが間違っている・足りない * 徐々にずれていく * + システムの更新タイミングとドキュメントの更新タイミングに差がある + </simpara> + <simpara> + システムとドキュメントは対応関係がある * 間違ったドキュメント * + 存在しないドキュメント + </simpara> + <simpara> + システムとドキュメントの乖離を定量化する 継続的に + システムの更新に近いタイミングで ドキュメントを更新し続ける + </simpara> + <simpara> + Documentation as Code + </simpara> + <simpara> + コードと同じツールでドキュメントを書く * issue tracker * vcs * plain + text markup * automation + </simpara> + <simpara> + 開発者 システム ドキュメント 構造化データ ソフトウェア + </simpara> + <simpara> + システムから構造化データを抽出する PHPDoc OpenAPI + </simpara> + <simpara> + ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する + </simpara> + <simpara> + ビューの単位でドキュメントに + </simpara> + <simpara> + スタックトレースからのドキュメント生成 + </simpara> + </blockquote> + <simpara> + ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な + (乖離しない) + 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。 + </simpara> + </section> + <section xml:id="_1410_a"> + <title>14:10 [A]</title> + <simpara> + cookie による session 管理 + </simpara> + <simpara> + 全体的に基本的な話だったので特に触れない。Cookie + やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。 + </simpara> + </section> + <section xml:id="_1450_a"> + <title>14:50 [A]</title> + <simpara> + PHP のエラーと例外 + </simpara> + <blockquote> + <simpara> + エラー PHPエンジンがエラーを通知する 例外 プログラムが投げる + </simpara> + <simpara> + PHP7-8とエラー + </simpara> + <simpara> + PHPエンジンのエラーの一部が に変換されるようになった → try-catch + で捕捉できる + </simpara> + <simpara> + は例外とは異なる + </simpara> + <simpara> + PHP8 でエラーレベルの引き上げ + </simpara> + <itemizedlist> + <listitem> + 捕捉すべきもの + <itemizedlist> + <listitem>recoverable</listitem> + </itemizedlist> + </listitem> + <listitem> + 捕捉すべきでないもの + <itemizedlist> + <listitem>unrecoverable</listitem> + <listitem>開発時に対処できるもの</listitem> + </itemizedlist> + </listitem> + </itemizedlist> + <simpara> + 例外 * 捕捉して事後処理 * 捕捉せず(or 捕捉した上で)さらに上に是非を問う + </simpara> + <simpara> + 開発段階で例外を把握し、ハンドリングを考えておく + </simpara> + <simpara> + と + </simpara> + <simpara> + はキャッチすべきでない + </simpara> + <itemizedlist> + <listitem> + <simpara> + + </simpara> + <itemizedlist> + <listitem>本番で起きてはいけない</listitem> + </itemizedlist> + </listitem> + <listitem> + <simpara> + + </simpara> + <itemizedlist> + <listitem>本番で起きてはいけない →生じないのだから捕捉もしない</listitem> + </itemizedlist> + </listitem> + <listitem> + <simpara> + + </simpara> + <itemizedlist> + <listitem>起こるかもしれないので本番環境でも考慮する</listitem> + </itemizedlist> + </listitem> + </itemizedlist> + <simpara> + 捕捉して対応するのではなく、未然に防ぐ + </simpara> + <simpara> + 独自例外を使う を投げてしまうと、 catch ()せざるを得ない →catch + 範囲が広すぎる + </simpara> + <simpara> + SPL の例外を使う + </simpara> + <simpara> + 例外翻訳 + 上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する + 下位レイヤの知識に依存させない + </simpara> + <simpara> + @throws 捕捉してほしい例外を書き連ねておく + </simpara> + <simpara> + 呼び出しもとに負わせたい責任 + </simpara> + </blockquote> + <simpara> + PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で + PHP を書き始めてから 4ヶ月ほどになる)。 + </simpara> + <simpara> + 個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell + などのエラーを「値として」扱う言語だと思っている。try-catch + は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は + C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる + (C のそれはまともな型付けではない。念のため)。 + </simpara> + <simpara> + PHP + のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。 + </simpara> + </section> + <section xml:id="_1530_a"> + <title>15:30 [A]</title> + <simpara> + Laravel のメール認証 + </simpara> + <simpara> + Laravel + の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。 + </simpara> + </section> + <section xml:id="_1610_a"> + <title>16:10 [A]</title> + <simpara> + gRPC + </simpara> + <blockquote> + <simpara> + Unary RPCs Server streaming RPCs Client streaming RPCs Bidirectional + streaming RPCs + </simpara> + <simpara> + Protobuf + </simpara> + <simpara> + 実装とAPIが乖離しにくい 自動生成 複数言語でも相互に使える + </simpara> + <simpara> + マイクロサービスのサービス通信 スマホアプリ ゲームサーバ + </simpara> + <simpara> + PHP では? + </simpara> + <simpara> + PHP ではストリーミングが難しい リクエストごとにプロセスが使い捨て + </simpara> + <simpara> + PHP ではgRPCのクライアントしか対応していない + </simpara> + <simpara> + gRPC-Web ブラウザで扱うためのJSライブラリ+プロトコル + </simpara> + <simpara> + HTTP/1.1 でも使える Unary RPC と Server streaming RPC のみ + </simpara> + <simpara> + Envoy Nginx などで相互に gRPC と gRPC-Web で変換 + </simpara> + <simpara> + Amp イベント駆動な並行処理のフレームワーク + </simpara> + <simpara> + HTTP/2 対応 + </simpara> + <simpara> + C#のgRPC-Webが楽 + </simpara> + </blockquote> + <simpara> + (発表の中でもまさに同じことをおっしゃっていたが) PHP + 以外の方が向いているだろう、というのが第一の感想である。gRPC + はそれ自体というよりも Protobuf + というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。 + </simpara> + </section> + <section xml:id="_1650_a"> + <title>16:50 [A]</title> + <simpara> + アーキテクチャテスト + </simpara> + <blockquote> + <simpara> + Independent Core Layer Pattern + </simpara> + <simpara> + 開発初期のアーキテクチャが崩れる + アーキテクチャ観点のコードレビューができない + </simpara> + <simpara> + どこにクラスを置けばよいか? ドキュメントがない + </simpara> + <simpara> + アーキテクチャ設計に関する知識が属人化・暗黙知化 + </simpara> + <simpara> + ガイドライン * 最初にルールを決めるのは簡単 * + ルール通り作り始めるのも簡単 * + →維持するのが難しい、人が決めたものゆえ壊れやすい + </simpara> + <simpara> + PHP の特性 * クラスは public * 可視性の制御が public / protected / + private のみ * 依存関係の制御が困難 + </simpara> + <simpara> + アーキテクチャテスト + クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する + </simpara> + <itemizedlist> + <listitem>deptrac</listitem> + <listitem>phpat</listitem> + </itemizedlist> + <simpara> + Independent Core Layer Pattern + </simpara> + <simpara> + アーキテクチャテストの失敗 * 実装誤り * or アーキテクチャが適切でない * + 開発の過程でフィードバックしていく + </simpara> + <simpara> + モジュラーモノリス→マイクロサービスへ + </simpara> + </blockquote> + </section> + </section> + <section xml:id="_day_2_20210328"> + <title>Day 2 (2021/03/28)</title> + <simpara> + 冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。 + </simpara> + <simpara> + 残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。 + </simpara> + </section> + <section xml:id="_全体の感想"> + <title>全体の感想</title> + <simpara> + Day 2 + にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも + (特に初参加者として) 嬉しいポイントだった。 + </simpara> + <simpara> + 今回、雑談/登壇者への質問等向けに Discord + サーバもあったのだが、こちらは参加こそしたものの ROM + のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord + 表示に + 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった + (さらにいうと Zoom + でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。 + </simpara> + <simpara> + 1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord + しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 + まあ初カンファレンスだし、とお茶を濁しておこう。 + </simpara> + <simpara> + さて、カンファレンスで一つ気になったことがある。それは、Discord + という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord + の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord + があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。 + </simpara> + <simpara> + <hr/> + </simpara> + <simpara> + 最後になりましたが、毎年の PHPerKaigi + 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました! + (ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い) + </simpara> + <simpara> + ではまた来年。 + </simpara> + </section> + </section> </article> diff --git a/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.xml b/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.xml index 4ee22fe..7f5fc66 100644 --- a/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.xml +++ b/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.xml @@ -16,89 +16,131 @@ </revision> </revhistory> </info> - <simpara>この記事は Qiita から移植してきたものです。 元 URL: - <link xl:href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</link></simpara> -<simpara><hr/></simpara> -<simpara>タイトル落ち。まずはこのコードを見て欲しい。</simpara> -<programlisting language="cpp" linenumbering="unnumbered">#include <iostream> + <simpara> + この記事は Qiita から移植してきたものです。 元 URL: + <link xl:href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</link> + </simpara> + <simpara> + <hr/> + </simpara> + <simpara> + タイトル落ち。まずはこのコードを見て欲しい。 + </simpara> + <programlisting language="cpp" linenumbering="unnumbered"> + <![CDATA[ + #include <iostream> -[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]] -[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]] -[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]] -[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]] -[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]] -[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]] -[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]] -[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]] -[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]] -[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]] -[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]] -[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]] -[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]] -// [[using]] -int main() { -std::cout << "Hello, World!" << std::endl; -}</programlisting> -<blockquote> - <simpara>コンパイラのバージョン $ 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</simpara> -<simpara>コンパイルコマンド (C17指定) $ clang –std=c++17 hoge.cpp</simpara> -</blockquote> -<simpara>この記事から得られるものはこれ以上ないので以下は蛇足になる。</simpara> -<simpara>別件で cppreference.com の -<link xl:href="https://en.cppreference.com/w/cpp/language/identifiers">identifier -のページ</link> を読んでいた時、次の文が目に止まった。</simpara> -<blockquote> + [[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]] + [[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]] + [[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]] + [[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]] + [[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]] + [[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]] + [[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]] + [[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]] + [[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]] + [[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]] + [[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]] + [[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]] + [[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]] + // [[using]] + int main() { + std::cout << "Hello, World!" << std::endl; + } + ]]> + </programlisting> + <blockquote> + <simpara> + コンパイラのバージョン $ 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 + </simpara> + <simpara> + コンパイルコマンド (C17指定) $ clang –std=c++17 hoge.cpp + </simpara> + </blockquote> + <simpara> + この記事から得られるものはこれ以上ないので以下は蛇足になる。 + </simpara> + <simpara> + 別件で cppreference.com の + <link xl:href="https://en.cppreference.com/w/cpp/language/identifiers">identifier + のページ</link> を読んでいた時、次の文が目に止まった。 + </simpara> + <blockquote> + <itemizedlist> + <listitem> + the identifiers that are keywords cannot be used for other purposes; + <itemizedlist> + <listitem> + 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) + </listitem> + </itemizedlist> + </listitem> + </itemizedlist> + </blockquote> + <simpara> + キーワードでも属性として指定する場合は非キーワードとして使えるらしい。 + 実際にやってみる。 + </simpara> + <simpara> + 同サイトの <link xl:href="https://en.cppreference.com/w/cpp/keyword">keywords のページ</link> + から一覧を拝借し、上のコードが出来上がった (C++17 + においてキーワードでないものなど、一部省いている)。 大量の警告 (unknown + attribute `〇〇' ignored) + がコンパイラから出力されるが、コンパイルできる。 + </simpara> + <simpara> + 上のコードでは <literal>[[using]]</literal> をコメントアウトしているが、これは <literal>using</literal> + キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。 + </simpara> + <programlisting language="cpp" linenumbering="unnumbered"> + <![CDATA[ + // using の例 + [[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文 + ]]> + </programlisting> + <simpara> + C++17 の仕様も見てみる (正確には標準化前のドラフト)。 + </simpara> + <simpara> + 引用元: <link xl:href="https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4">https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4</link> + </simpara> + <blockquote> + <simpara> + 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. + </simpara> + </blockquote> + <simpara> + 「<literal>identifier</literal> の構文上の要件を満たすキーワードまたは代替トークンが + <literal>attribute-token</literal> に含まれている場合、<literal>identifier</literal> + とみなされる」とある。どうやら間違いないようだ。 + </simpara> + <simpara> + ところで、代替トークン (alternative token) とは <literal>and</literal> (<literal>&</literal>) や <literal>bitor</literal> + (<literal>|</literal>) などのことだが、<literal>identifier</literal> + の構文上の要件を満たさないような代替トークンなどあるのか? + 疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい + (参考: + <link xl:href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</link>) + </simpara> <itemizedlist> - <listitem> - the identifiers that are keywords cannot be used for other purposes; - <itemizedlist> - <listitem> - 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) - </listitem> - </itemizedlist> - </listitem> + <listitem><literal><%</literal> → <literal>{</literal></listitem> + <listitem><literal>%></literal> → <literal>}</literal></listitem> + <listitem><literal><:</literal> → <literal>[</literal></listitem> + <listitem><literal>:></literal> → <literal>]</literal></listitem> + <listitem><literal>%:</literal> → <literal>#</literal></listitem> + <listitem><literal>%:%:</literal> → <literal>##</literal></listitem> </itemizedlist> -</blockquote> -<simpara>キーワードでも属性として指定する場合は非キーワードとして使えるらしい。 -実際にやってみる。</simpara> -<simpara>同サイトの <link xl:href="https://en.cppreference.com/w/cpp/keyword">keywords のページ</link> - から一覧を拝借し、上のコードが出来上がった (C++17 - においてキーワードでないものなど、一部省いている)。 大量の警告 (unknown - attribute `〇〇' ignored) - がコンパイラから出力されるが、コンパイルできる。</simpara> -<simpara>上のコードでは <literal>[[using]]</literal> をコメントアウトしているが、これは <literal>using</literal> - キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。</simpara> -<programlisting language="cpp" linenumbering="unnumbered">// using の例 -[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文</programlisting> -<simpara>C++17 の仕様も見てみる (正確には標準化前のドラフト)。</simpara> -<simpara>引用元: <link xl:href="https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4">https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4</link></simpara> -<blockquote> - <simpara>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.</simpara> -</blockquote> -<simpara>「<literal>identifier</literal> の構文上の要件を満たすキーワードまたは代替トークンが -<literal>attribute-token</literal> に含まれている場合、<literal>identifier</literal> -とみなされる」とある。どうやら間違いないようだ。</simpara> -<simpara>ところで、代替トークン (alternative token) とは <literal>and</literal> (<literal>&</literal>) や <literal>bitor</literal> - (<literal>|</literal>) などのことだが、<literal>identifier</literal> - の構文上の要件を満たさないような代替トークンなどあるのか? - 疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい - (参考: - <link xl:href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</link>)</simpara> -<itemizedlist> - <listitem><literal><%</literal> → <literal>{</literal></listitem> - <listitem><literal>%></literal> → <literal>}</literal></listitem> - <listitem><literal><:</literal> → <literal>[</literal></listitem> - <listitem><literal>:></literal> → <literal>]</literal></listitem> - <listitem><literal>%:</literal> → <literal>#</literal></listitem> - <listitem><literal>%:%:</literal> → <literal>##</literal></listitem> -</itemizedlist> -<simpara>「<literal>identifier</literal> - の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。</simpara> -<simpara>調べた感想: 字句解析器か構文解析器が辛そう</simpara> + <simpara> + 「<literal>identifier</literal> + の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。 + </simpara> + <simpara> + 調べた感想: 字句解析器か構文解析器が辛そう + </simpara> </article> diff --git a/content/posts/2021-10-02/python-unbound-local-error.xml b/content/posts/2021-10-02/python-unbound-local-error.xml index 3d33628..7cf9b1a 100644 --- a/content/posts/2021-10-02/python-unbound-local-error.xml +++ b/content/posts/2021-10-02/python-unbound-local-error.xml @@ -16,45 +16,75 @@ </revision> </revhistory> </info> - <simpara>この記事は Qiita から移植してきたものです。 元 URL: - <link xl:href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</link></simpara> -<simpara><hr/></simpara> -<simpara>本記事は Python 3.7.6 の動作結果を元にして書かれている。</simpara> -<simpara>Python でクロージャを作ろうと、次のようなコードを書いた。</simpara> -<programlisting language="python" linenumbering="unnumbered">def f(): -x = 0 -def g(): -x += 1 -g() + <simpara> + この記事は Qiita から移植してきたものです。 元 URL: + <link xl:href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</link> + </simpara> + <simpara> + <hr/> + </simpara> + <simpara> + 本記事は Python 3.7.6 の動作結果を元にして書かれている。 + </simpara> + <simpara> + Python でクロージャを作ろうと、次のようなコードを書いた。 + </simpara> + <programlisting language="python" linenumbering="unnumbered"> + <![CDATA[ + def f(): + x = 0 + def g(): + x += 1 + g() -f()</programlisting> -<simpara>関数 <literal>g</literal> から 関数 <literal>f</literal> のスコープ内で定義された変数 <literal>x</literal> を参照し、それに -1 を足そうとしている。 これを実行すると <literal>x += 1</literal> -の箇所でエラーが発生する。</simpara> -<blockquote> - <simpara>UnboundLocalError: local variable `x' referenced before assignment</simpara> -</blockquote> -<simpara>local変数 <literal>x</literal> が代入前に参照された、とある。これは、<literal>f</literal> の <literal>x</literal> - を参照するのではなく、新しく別の変数を <literal>g</literal> 内に作ってしまっているため。 - 前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<literal>var</literal> - を変数宣言のための構文として擬似的に利用している。</simpara> -<programlisting language="python" linenumbering="unnumbered"># 注: var は正しい Python の文法ではない。上記参照のこと -def f(): -var x # f の local変数 'x' を宣言 -x = 0 # x に 0 を代入 -def g(): # f の内部関数 g を定義 -var x # g の local変数 'x' を宣言 -# たまたま f にも同じ名前の変数があるが、それとは別の変数 -x += 1 # x に 1 を加算 (x = x + 1 の糖衣構文) -# 加算する前の値を参照しようとするが、まだ代入されていないためエラー -g()</programlisting> -<simpara>当初の意図を表現するには、次のように書けばよい。</simpara> -<programlisting language="python" linenumbering="unnumbered">def f(): -x = 0 -def g(): -nonlocal x ## (*) -x += 1 -g()</programlisting> -<simpara><literal>(*)</literal> のように、<literal>nonlocal</literal> を追加する。これにより一つ外側のスコープ (<literal>g</literal> - の一つ外側 = <literal>f</literal>) で定義されている <literal>x</literal> を探しに行くようになる。</simpara> + f() + ]]> + </programlisting> + <simpara> + 関数 <literal>g</literal> から 関数 <literal>f</literal> のスコープ内で定義された変数 <literal>x</literal> を参照し、それに + 1 を足そうとしている。 これを実行すると <literal>x += 1</literal> + の箇所でエラーが発生する。 + </simpara> + <blockquote> + <simpara> + UnboundLocalError: local variable `x' referenced before assignment + </simpara> + </blockquote> + <simpara> + local変数 <literal>x</literal> が代入前に参照された、とある。これは、<literal>f</literal> の <literal>x</literal> + を参照するのではなく、新しく別の変数を <literal>g</literal> 内に作ってしまっているため。 + 前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<literal>var</literal> + を変数宣言のための構文として擬似的に利用している。 + </simpara> + <programlisting language="python" linenumbering="unnumbered"> + <![CDATA[ + # 注: var は正しい Python の文法ではない。上記参照のこと + def f(): + var x # f の local変数 'x' を宣言 + x = 0 # x に 0 を代入 + def g(): # f の内部関数 g を定義 + var x # g の local変数 'x' を宣言 + # たまたま f にも同じ名前の変数があるが、それとは別の変数 + x += 1 # x に 1 を加算 (x = x + 1 の糖衣構文) + # 加算する前の値を参照しようとするが、まだ代入されていないためエラー + g() + ]]> + </programlisting> + <simpara> + 当初の意図を表現するには、次のように書けばよい。 + </simpara> + <programlisting language="python" linenumbering="unnumbered"> + <![CDATA[ + def f(): + x = 0 + def g(): + nonlocal x ## (*) + x += 1 + g() + ]]> + </programlisting> + <simpara> + <literal>(*)</literal> のように、<literal>nonlocal</literal> を追加する。これにより一つ外側のスコープ (<literal>g</literal> + の一つ外側 = <literal>f</literal>) で定義されている <literal>x</literal> を探しに行くようになる。 + </simpara> </article> diff --git a/content/posts/2021-10-02/ruby-detect-running-implementation.xml b/content/posts/2021-10-02/ruby-detect-running-implementation.xml index ccc797b..18548c2 100644 --- a/content/posts/2021-10-02/ruby-detect-running-implementation.xml +++ b/content/posts/2021-10-02/ruby-detect-running-implementation.xml @@ -15,81 +15,111 @@ </revision> </revhistory> </info> - <simpara>この記事は Qiita から移植してきたものです。 元 URL: - <link xl:href="https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791">https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791</link></simpara> -<simpara><hr/></simpara> -<simpara>Ruby -という言語には複数の実装があるが、それらをスクリプト上からどのようにして -programmatically に見分ければよいだろうか。</simpara> -<simpara><literal>Object</literal> クラスに定義されている <literal>RUBY_ENGINE</literal> - という定数がこの用途に使える。</simpara> -<simpara>参考: -<link xl:href="https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_ENGINE.html">Object::RUBY_ENGINE</link></simpara> -<simpara>上記ページの例から引用する:</simpara> -<programlisting language="shell-session" linenumbering="unnumbered">$ ruby-1.9.1 -ve 'p RUBY_ENGINE' -ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux] -"ruby" -$ jruby -ve 'p RUBY_ENGINE' -jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] -"jruby"</programlisting> -<simpara>それぞれの処理系がどのような値を返すかだが、stack overflow -に良い質問と回答があった。</simpara> -<simpara><link xl:href="https://stackoverflow.com/a/9894232">What values for RUBY_ENGINE -correspond to which Ruby implementations?</link> より引用:</simpara> -<blockquote> - <table> - <thead> - <tr> - <td>RUBY_ENGINE</td> - <td>Implementation</td> - </tr> - </thead> - <tbody> - <tr> - <td><undefined></td> - <td>MRI < 1.9</td> - </tr> - <tr> - <td>`ruby'</td> - <td>MRI >= 1.9 or REE</td> - </tr> - <tr> - <td>`jruby'</td> - <td>JRuby</td> - </tr> - <tr> - <td>`macruby'</td> - <td>MacRuby</td> - </tr> - <tr> - <td>`rbx'</td> - <td>Rubinius</td> - </tr> - <tr> - <td>`maglev'</td> - <td>MagLev</td> - </tr> - <tr> - <td>`ironruby'</td> - <td>IronRuby</td> - </tr> - <tr> - <td>`cardinal'</td> - <td>Cardinal</td> - </tr> - </tbody> - </table> -</blockquote> -<simpara>なお、この質問・回答は -2014年になされたものであり、値は変わっている可能性がある。MRI (aka -CRuby) については執筆時現在 (2020/12/8) も <literal>'ruby'</literal> -が返ってくることを確認済み。</simpara> -<simpara>この表にない主要な処理系として、https://mruby.org[mruby] は <literal>'mruby'</literal> - を返す。</simpara> -<simpara><link xl:href="https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35">mruby -該当部分のソース</link> より引用:</simpara> -<programlisting language="c" linenumbering="unnumbered">/* -* Ruby engine. -*/ -#define MRUBY_RUBY_ENGINE "mruby"</programlisting> + <simpara> + この記事は Qiita から移植してきたものです。 元 URL: + <link xl:href="https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791">https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791</link> + </simpara> + <simpara> + <hr/> + </simpara> + <simpara> + Ruby + という言語には複数の実装があるが、それらをスクリプト上からどのようにして + programmatically に見分ければよいだろうか。 + </simpara> + <simpara> + <literal>Object</literal> クラスに定義されている <literal>RUBY_ENGINE</literal> + という定数がこの用途に使える。 + </simpara> + <simpara> + 参考: + <link xl:href="https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_ENGINE.html">Object::RUBY_ENGINE</link> + </simpara> + <simpara> + 上記ページの例から引用する: + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ ruby-1.9.1 -ve 'p RUBY_ENGINE' + ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux] + "ruby" + $ jruby -ve 'p RUBY_ENGINE' + jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] + "jruby" + ]]> + </programlisting> + <simpara> + それぞれの処理系がどのような値を返すかだが、stack overflow + に良い質問と回答があった。 + </simpara> + <simpara> + <link xl:href="https://stackoverflow.com/a/9894232">What values for RUBY_ENGINE + correspond to which Ruby implementations?</link> より引用: + </simpara> + <blockquote> + <table> + <thead> + <tr> + <td>RUBY_ENGINE</td> + <td>Implementation</td> + </tr> + </thead> + <tbody> + <tr> + <td><undefined></td> + <td>MRI < 1.9</td> + </tr> + <tr> + <td>`ruby'</td> + <td>MRI >= 1.9 or REE</td> + </tr> + <tr> + <td>`jruby'</td> + <td>JRuby</td> + </tr> + <tr> + <td>`macruby'</td> + <td>MacRuby</td> + </tr> + <tr> + <td>`rbx'</td> + <td>Rubinius</td> + </tr> + <tr> + <td>`maglev'</td> + <td>MagLev</td> + </tr> + <tr> + <td>`ironruby'</td> + <td>IronRuby</td> + </tr> + <tr> + <td>`cardinal'</td> + <td>Cardinal</td> + </tr> + </tbody> + </table> + </blockquote> + <simpara> + なお、この質問・回答は + 2014年になされたものであり、値は変わっている可能性がある。MRI (aka + CRuby) については執筆時現在 (2020/12/8) も <literal>'ruby'</literal> + が返ってくることを確認済み。 + </simpara> + <simpara> + この表にない主要な処理系として、https://mruby.org[mruby] は <literal>'mruby'</literal> + を返す。 + </simpara> + <simpara> + <link xl:href="https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35">mruby + 該当部分のソース</link> より引用: + </simpara> + <programlisting language="c" linenumbering="unnumbered"> + <![CDATA[ + /* + * Ruby engine. + */ + #define MRUBY_RUBY_ENGINE "mruby" + ]]> + </programlisting> </article> diff --git a/content/posts/2021-10-02/ruby-then-keyword-and-case-in.xml b/content/posts/2021-10-02/ruby-then-keyword-and-case-in.xml index 2901e44..40ac316 100644 --- a/content/posts/2021-10-02/ruby-then-keyword-and-case-in.xml +++ b/content/posts/2021-10-02/ruby-then-keyword-and-case-in.xml @@ -16,174 +16,258 @@ </revision> </revhistory> </info> - <simpara>この記事は Qiita から移植してきたものです。 元 URL: - <link xl:href="https://qiita.com/nsfisis/items/787a8cf888a304497223">https://qiita.com/nsfisis/items/787a8cf888a304497223</link></simpara> -<simpara><hr/></simpara> -<section xml:id="_tl_dr"> - <title>TL; DR</title> - <simpara><literal>case</literal> - <literal>in</literal> によるパターンマッチング構文でも、<literal>case</literal> - <literal>when</literal> - と同じように <literal>then</literal> が使える (場合によっては使う必要がある)。</simpara> -</section> -<section xml:id="_then_とは"> - <title><literal>then</literal> とは</title> - <simpara>使われることは稀だが、Ruby では <literal>then</literal> - がキーワードになっている。次のように使う:</simpara> - <programlisting language="ruby" linenumbering="unnumbered">if cond then - puts "Y" - else - puts "N" - end</programlisting> -<simpara>このキーワードが現れうる場所はいくつかあり、<literal>if</literal>、<literal>unless</literal>、<literal>rescue</literal>、<literal>case</literal> - 構文がそれに当たる。 上記のように、何か条件を書いた後 <literal>then</literal> - を置き、式がそこで終了していることを示すマーカーとして機能する。</simpara> -<programlisting language="ruby" linenumbering="unnumbered"># Example: + <simpara> + この記事は Qiita から移植してきたものです。 元 URL: + <link xl:href="https://qiita.com/nsfisis/items/787a8cf888a304497223">https://qiita.com/nsfisis/items/787a8cf888a304497223</link> + </simpara> + <simpara> + <hr/> + </simpara> + <section xml:id="_tl_dr"> + <title>TL; DR</title> + <simpara> + <literal>case</literal> - <literal>in</literal> によるパターンマッチング構文でも、<literal>case</literal> - <literal>when</literal> + と同じように <literal>then</literal> が使える (場合によっては使う必要がある)。 + </simpara> + </section> + <section xml:id="_then_とは"> + <title><literal>then</literal> とは</title> + <simpara> + 使われることは稀だが、Ruby では <literal>then</literal> + がキーワードになっている。次のように使う: + </simpara> + <programlisting language="ruby" linenumbering="unnumbered"> + <![CDATA[ + if cond then + puts "Y" + else + puts "N" + end + ]]> + </programlisting> + <simpara> + このキーワードが現れうる場所はいくつかあり、<literal>if</literal>、<literal>unless</literal>、<literal>rescue</literal>、<literal>case</literal> + 構文がそれに当たる。 上記のように、何か条件を書いた後 <literal>then</literal> + を置き、式がそこで終了していることを示すマーカーとして機能する。 + </simpara> + <programlisting language="ruby" linenumbering="unnumbered"> + <![CDATA[ + # Example: -if x then -a -end + if x then + a + end -unless x then -a -end + unless x then + a + end -begin -a -rescue then -b -end + begin + a + rescue then + b + end -case x -when p then -a -end</programlisting> -</section> -<section xml:id="_なぜ普段は書かなくてもよいのか"> - <title>なぜ普段は書かなくてもよいのか</title> - <simpara>普通 Ruby のコードで <literal>then</literal> - を書くことはない。なぜか。次のコードを実行してみるとわかる。</simpara> - <programlisting language="ruby" linenumbering="unnumbered">if true puts 'Hello, World!' end</programlisting> - <simpara>次のような構文エラーが出力される。</simpara> - <literallayout class="monospaced"> - <![CDATA[ + case x + when p then + a + end + ]]> + </programlisting> + </section> + <section xml:id="_なぜ普段は書かなくてもよいのか"> + <title>なぜ普段は書かなくてもよいのか</title> + <simpara> + 普通 Ruby のコードで <literal>then</literal> + を書くことはない。なぜか。次のコードを実行してみるとわかる。 + </simpara> + <programlisting language="ruby" linenumbering="unnumbered"> + <![CDATA[ + if true puts 'Hello, World!' end + ]]> + </programlisting> + <simpara> + 次のような構文エラーが出力される。 + </simpara> + <literallayout class="monospaced"> + <![CDATA[ 20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n' if true puts 'Hello, World!' end ^~~~ 20:1: syntax error, unexpected `end', expecting end-of-input ...f true puts 'Hello, World!' end - ]]> - </literallayout> -<simpara>二つ目のメッセージは無視して一つ目を読むと、<literal>then</literal> か <literal>;</literal> - か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。</simpara> -<simpara>ポイントは改行が <literal>then</literal> (や <literal>;</literal>) の代わりとなることである。<literal>true</literal> - の後に改行を入れてみる。</simpara> -<programlisting language="ruby" linenumbering="unnumbered">if true -puts 'Hello, World!' end</programlisting> -<simpara>無事 Hello, World! と出力されるようになった。</simpara> -</section> -<section xml:id="_なぜ_then_や_や改行が必要か"> - <title>なぜ <literal>then</literal> や <literal>;</literal> や改行が必要か</title> - <simpara>なぜ <literal>then</literal> や <literal>;</literal> や改行 (以下 「<literal>then</literal> 等」) - が必要なのだろうか。次の例を見てほしい:</simpara> -<programlisting language="ruby" linenumbering="unnumbered">if a b end</programlisting> -<simpara><literal>then</literal> も <literal>;</literal> - も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。 - この例は二通りに解釈できる。</simpara> -<programlisting language="ruby" linenumbering="unnumbered"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価 -if a then -b -end</programlisting> -<programlisting language="ruby" linenumbering="unnumbered"># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、 -# その結果が truthy なら何もしない -if a(b) then -end</programlisting> -<simpara><literal>then</literal> 等はこの曖昧性を排除するためにあり、条件式は <literal>if</literal> から <literal>then</literal> - 等までの間にある、ということを明確にする。 C系の <literal>if</literal> 後に来る <literal>(</literal>/<literal>)</literal> - や、Python の <literal>:</literal>、Rust/Go/Swift などの <literal>{</literal> も同じ役割を持つ。</simpara> -<simpara>Ruby の場合、プログラマーが書きやすいよう改行でもって <literal>then</literal> - が代用できるので、ほとんどの場合 <literal>then</literal> は必要ない。</simpara> -</section> -<section xml:id="_case_in_における_then"> - <title><literal>case</literal> - <literal>in</literal> における <literal>then</literal></title> - <simpara>ようやく本題にたどり着いた。来る Ruby 3.0 では <literal>case</literal> と <literal>in</literal> - キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして - <literal>then</literal> 等が必要になる。 (現在の) Ruby には formal - な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc - の説明は省略)。</simpara> - <simpara><link xl:href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</link></simpara> - <programlisting language="yacc" linenumbering="unnumbered">p_case_body : keyword_in - { - SET_LEX_STATE(EXPR_BEG|EXPR_LABEL); - p->command_start = FALSE; - $<ctxt>1 = p->ctxt; - p->ctxt.in_kwarg = 1; - $<tbl>$ = push_pvtbl(p); - } - { - $<tbl>$ = push_pktbl(p); - } - p_top_expr then - { - pop_pktbl(p, $<tbl>3); - pop_pvtbl(p, $<tbl>2); - p->ctxt.in_kwarg = $<ctxt>1.in_kwarg; - } - compstmt - p_cases - { - /*%%%*/ - $$ = NEW_IN($4, $7, $8, &@$); - /*% %*/ - /*% ripper: in!($4, $7, escape_Qundef($8)) %*/ - } - ;</programlisting> -<simpara>簡略版:</simpara> -<programlisting language="yacc" linenumbering="unnumbered">p_case_body : keyword_in p_top_expr then compstmt p_cases -;</programlisting> -<simpara>ここで、<literal>keyword_in</literal> は文字通り <literal>in</literal>、<literal>p_top_expr</literal> - はいわゆるパターン、<literal>then</literal> は <literal>then</literal> - キーワードのことではなく、この記事で <literal>then</literal> 等と呼んでいるもの、つまり - <literal>then</literal> キーワード、<literal>;</literal>、改行のいずれかである。</simpara> -<simpara>これにより、<literal>case</literal> - <literal>when</literal> による従来の構文と同じように、<literal>then</literal> - 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:</simpara> -<programlisting language="ruby" linenumbering="unnumbered">case x -in 1 then a -in 2 then b -in 3 then c -end + ]]> + </literallayout> + <simpara> + 二つ目のメッセージは無視して一つ目を読むと、<literal>then</literal> か <literal>;</literal> + か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。 + </simpara> + <simpara> + ポイントは改行が <literal>then</literal> (や <literal>;</literal>) の代わりとなることである。<literal>true</literal> + の後に改行を入れてみる。 + </simpara> + <programlisting language="ruby" linenumbering="unnumbered"> + <![CDATA[ + if true + puts 'Hello, World!' end + ]]> + </programlisting> + <simpara> + 無事 Hello, World! と出力されるようになった。 + </simpara> + </section> + <section xml:id="_なぜ_then_や_や改行が必要か"> + <title>なぜ <literal>then</literal> や <literal>;</literal> や改行が必要か</title> + <simpara> + なぜ <literal>then</literal> や <literal>;</literal> や改行 (以下 「<literal>then</literal> 等」) + が必要なのだろうか。次の例を見てほしい: + </simpara> + <programlisting language="ruby" linenumbering="unnumbered"> + <![CDATA[ + if a b end + ]]> + </programlisting> + <simpara> + <literal>then</literal> も <literal>;</literal> + も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。 + この例は二通りに解釈できる。 + </simpara> + <programlisting language="ruby" linenumbering="unnumbered"> + <![CDATA[ + # a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価 + if a then + b + end + ]]> + </programlisting> + <programlisting language="ruby" linenumbering="unnumbered"> + <![CDATA[ + # a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、 + # その結果が truthy なら何もしない + if a(b) then + end + ]]> + </programlisting> + <simpara> + <literal>then</literal> 等はこの曖昧性を排除するためにあり、条件式は <literal>if</literal> から <literal>then</literal> + 等までの間にある、ということを明確にする。 C系の <literal>if</literal> 後に来る <literal>(</literal>/<literal>)</literal> + や、Python の <literal>:</literal>、Rust/Go/Swift などの <literal>{</literal> も同じ役割を持つ。 + </simpara> + <simpara> + Ruby の場合、プログラマーが書きやすいよう改行でもって <literal>then</literal> + が代用できるので、ほとんどの場合 <literal>then</literal> は必要ない。 + </simpara> + </section> + <section xml:id="_case_in_における_then"> + <title><literal>case</literal> - <literal>in</literal> における <literal>then</literal></title> + <simpara> + ようやく本題にたどり着いた。来る Ruby 3.0 では <literal>case</literal> と <literal>in</literal> + キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして + <literal>then</literal> 等が必要になる。 (現在の) Ruby には formal + な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc + の説明は省略)。 + </simpara> + <simpara> + <link xl:href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</link> + </simpara> + <programlisting language="yacc" linenumbering="unnumbered"> + <![CDATA[ + p_case_body : keyword_in + { + SET_LEX_STATE(EXPR_BEG|EXPR_LABEL); + p->command_start = FALSE; + $<ctxt>1 = p->ctxt; + p->ctxt.in_kwarg = 1; + $<tbl>$ = push_pvtbl(p); + } + { + $<tbl>$ = push_pktbl(p); + } + p_top_expr then + { + pop_pktbl(p, $<tbl>3); + pop_pvtbl(p, $<tbl>2); + p->ctxt.in_kwarg = $<ctxt>1.in_kwarg; + } + compstmt + p_cases + { + /*%%%*/ + $$ = NEW_IN($4, $7, $8, &@$); + /*% %*/ + /*% ripper: in!($4, $7, escape_Qundef($8)) %*/ + } + ; + ]]> + </programlisting> + <simpara> + 簡略版: + </simpara> + <programlisting language="yacc" linenumbering="unnumbered"> + <![CDATA[ + p_case_body : keyword_in p_top_expr then compstmt p_cases + ; + ]]> + </programlisting> + <simpara> + ここで、<literal>keyword_in</literal> は文字通り <literal>in</literal>、<literal>p_top_expr</literal> + はいわゆるパターン、<literal>then</literal> は <literal>then</literal> + キーワードのことではなく、この記事で <literal>then</literal> 等と呼んでいるもの、つまり + <literal>then</literal> キーワード、<literal>;</literal>、改行のいずれかである。 + </simpara> + <simpara> + これにより、<literal>case</literal> - <literal>when</literal> による従来の構文と同じように、<literal>then</literal> + 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる: + </simpara> + <programlisting language="ruby" linenumbering="unnumbered"> + <![CDATA[ + case x + in 1 then a + in 2 then b + in 3 then c + end -case x -in 1 -a -in 2 -b -in 3 -c -end + case x + in 1 + a + in 2 + b + in 3 + c + end -case x -in 1; a -in 2; b -in 3; c -end</programlisting> -<simpara>ところで、<literal>p_top_expr</literal> には <literal>if</literal> による guard clause -が書けるので、その場合は <literal>if</literal> - <literal>then</literal> と似たような見た目になる。</simpara> -<programlisting language="ruby" linenumbering="unnumbered">case x -in 0 then a -in n if n < 0 then b -in n then c -end</programlisting> -</section> -<section xml:id="_まとめ"> - <title>まとめ</title> - <itemizedlist> - <listitem> - <literal>if</literal> や <literal>case</literal> の条件の後ろには <literal>then</literal>、<literal>;</literal>、改行のいずれかが必要 - <itemizedlist> - <listitem>通常は改行しておけばよい</listitem> - </itemizedlist> - </listitem> - <listitem>3.0 で入る予定の <literal>case</literal> - <literal>in</literal> でも <literal>then</literal> 等が必要になる</listitem> - <listitem>Ruby の構文を正確に知るには (現状) <literal>parse.y</literal> を直接読めばよい</listitem> - </itemizedlist> -</section> + case x + in 1; a + in 2; b + in 3; c + end + ]]> + </programlisting> + <simpara> + ところで、<literal>p_top_expr</literal> には <literal>if</literal> による guard clause + が書けるので、その場合は <literal>if</literal> - <literal>then</literal> と似たような見た目になる。 + </simpara> + <programlisting language="ruby" linenumbering="unnumbered"> + <![CDATA[ + case x + in 0 then a + in n if n < 0 then b + in n then c + end + ]]> + </programlisting> + </section> + <section xml:id="_まとめ"> + <title>まとめ</title> + <itemizedlist> + <listitem> + <literal>if</literal> や <literal>case</literal> の条件の後ろには <literal>then</literal>、<literal>;</literal>、改行のいずれかが必要 + <itemizedlist> + <listitem>通常は改行しておけばよい</listitem> + </itemizedlist> + </listitem> + <listitem>3.0 で入る予定の <literal>case</literal> - <literal>in</literal> でも <literal>then</literal> 等が必要になる</listitem> + <listitem>Ruby の構文を正確に知るには (現状) <literal>parse.y</literal> を直接読めばよい</listitem> + </itemizedlist> + </section> </article> diff --git a/content/posts/2021-10-02/rust-where-are-primitive-types-from.xml b/content/posts/2021-10-02/rust-where-are-primitive-types-from.xml index 35ec0c8..f395f4f 100644 --- a/content/posts/2021-10-02/rust-where-are-primitive-types-from.xml +++ b/content/posts/2021-10-02/rust-where-are-primitive-types-from.xml @@ -15,160 +15,226 @@ </revision> </revhistory> </info> - <simpara>この記事は Qiita から移植してきたものです。 元 URL: - <link xl:href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</link></simpara> -<simpara><hr/></simpara> -<section xml:id="_前置き"> - <title>前置き</title> - <simpara>Rust - において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。</simpara> -<programlisting language="rust" linenumbering="unnumbered">#![allow(non_camel_case_types)] -#![allow(dead_code)] + <simpara> + この記事は Qiita から移植してきたものです。 元 URL: + <link xl:href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</link> + </simpara> + <simpara> + <hr/> + </simpara> + <section xml:id="_前置き"> + <title>前置き</title> + <simpara> + Rust + において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。 + </simpara> + <programlisting language="rust" linenumbering="unnumbered"> + <![CDATA[ + #![allow(non_camel_case_types)] + #![allow(dead_code)] -struct bool; -struct char; -struct i8; -struct i16; -struct i32; -struct i64; -struct i128; -struct isize; -struct u8; -struct u16; -struct u32; -struct u64; -struct u128; -struct usize; -struct f32; -struct f64; -struct str;</programlisting> -<simpara>では、普段単に <literal>bool</literal> と書いたとき、この <literal>bool</literal> - は一体どこから来ているのか。rustc のソースを追ってみた。</simpara> -<blockquote> - <simpara>前提知識: 一般的なコンパイラの構造、用語。<literal>rustc</literal> そのものの知識は不要 - (というよりも筆者自身がよく知らない)</simpara> -</blockquote> -</section> -<section xml:id="_調査"> - <title>調査</title> - <simpara>調査に使用したソース (調査時点での最新 master)</simpara> - <simpara><link xl:href="https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98">https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98</link></simpara> - <simpara>どのようにして調べるか。rustc - の構造には詳しくないため、すぐに当たりをつけるのは難しい。</simpara> -<simpara>大雑把な構造としては、<literal>compiler</literal> フォルダ以下に <literal>rustc_*</literal> - という名前のクレートが数十個入っている。これがどうやら <literal>rustc</literal> - コマンドの実装部のようだ。</simpara> -<simpara><literal>rustc</literal> はセルフホストされている (= <literal>rustc</literal> 自身が Rust で書かれている) -ので、<literal>bool</literal> や <literal>char</literal> -などで適当に検索をかけてもノイズが多すぎて話にならない。 -しかし、お誂え向きなことに <literal>i128</literal>/<literal>u128</literal> -というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って -<literal>git grep</literal> してみる。</simpara> -<literallayout class="monospaced">$ git grep "\bi128\b" | wc # i128 -165 1069 15790 + struct bool; + struct char; + struct i8; + struct i16; + struct i32; + struct i64; + struct i128; + struct isize; + struct u8; + struct u16; + struct u32; + struct u64; + struct u128; + struct usize; + struct f32; + struct f64; + struct str; + ]]> + </programlisting> + <simpara> + では、普段単に <literal>bool</literal> と書いたとき、この <literal>bool</literal> + は一体どこから来ているのか。rustc のソースを追ってみた。 + </simpara> + <blockquote> + <simpara> + 前提知識: 一般的なコンパイラの構造、用語。<literal>rustc</literal> そのものの知識は不要 + (というよりも筆者自身がよく知らない) + </simpara> + </blockquote> + </section> + <section xml:id="_調査"> + <title>調査</title> + <simpara> + 調査に使用したソース (調査時点での最新 master) + </simpara> + <simpara> + <link xl:href="https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98">https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98</link> + </simpara> + <simpara> + どのようにして調べるか。rustc + の構造には詳しくないため、すぐに当たりをつけるのは難しい。 + </simpara> + <simpara> + 大雑把な構造としては、<literal>compiler</literal> フォルダ以下に <literal>rustc_*</literal> + という名前のクレートが数十個入っている。これがどうやら <literal>rustc</literal> + コマンドの実装部のようだ。 + </simpara> + <simpara> + <literal>rustc</literal> はセルフホストされている (= <literal>rustc</literal> 自身が Rust で書かれている) + ので、<literal>bool</literal> や <literal>char</literal> + などで適当に検索をかけてもノイズが多すぎて話にならない。 + しかし、お誂え向きなことに <literal>i128</literal>/<literal>u128</literal> + というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って + <literal>git grep</literal> してみる。 + </simpara> + <literallayout class="monospaced"> + <![CDATA[ + $ git grep "\bi128\b" | wc # i128 + 165 1069 15790 -$ git grep "\bu128\b" | wc # u128 -293 2127 26667 + $ git grep "\bu128\b" | wc # u128 + 293 2127 26667 -$ git grep "\bbool\b" | wc # cf. bool の結果 -3563 23577 294659</literallayout> -<simpara>165 -程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。</simpara> -<literallayout class="monospaced">$ git grep "\bi128\b" -... -rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128)); -...</literallayout> -<simpara><literal>rustc_resolve</literal> - というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。</simpara> -<programlisting language="rust" linenumbering="unnumbered">/// Interns the names of the primitive types. -/// -/// All other types are defined somewhere and possibly imported, but the primitive ones need -/// special handling, since they have no place of origin. -struct PrimitiveTypeTable { -primitive_types: FxHashMap<Symbol, PrimTy>, -} + $ git grep "\bbool\b" | wc # cf. bool の結果 + 3563 23577 294659 + ]]> + </literallayout> + <simpara> + 165 + 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。 + </simpara> + <literallayout class="monospaced"> + <![CDATA[ + $ git grep "\bi128\b" + ... + rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128)); + ... + ]]> + </literallayout> + <simpara> + <literal>rustc_resolve</literal> + というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。 + </simpara> + <programlisting language="rust" linenumbering="unnumbered"> + <![CDATA[ + /// Interns the names of the primitive types. + /// + /// All other types are defined somewhere and possibly imported, but the primitive ones need + /// special handling, since they have no place of origin. + struct PrimitiveTypeTable { + primitive_types: FxHashMap<Symbol, PrimTy>, + } -impl PrimitiveTypeTable { -fn new() -> PrimitiveTypeTable { -let mut table = FxHashMap::default(); + impl PrimitiveTypeTable { + fn new() -> PrimitiveTypeTable { + let mut table = FxHashMap::default(); -table.insert(sym::bool, Bool); -table.insert(sym::char, Char); -table.insert(sym::f32, Float(FloatTy::F32)); -table.insert(sym::f64, Float(FloatTy::F64)); -table.insert(sym::isize, Int(IntTy::Isize)); -table.insert(sym::i8, Int(IntTy::I8)); -table.insert(sym::i16, Int(IntTy::I16)); -table.insert(sym::i32, Int(IntTy::I32)); -table.insert(sym::i64, Int(IntTy::I64)); -table.insert(sym::i128, Int(IntTy::I128)); -table.insert(sym::str, Str); -table.insert(sym::usize, Uint(UintTy::Usize)); -table.insert(sym::u8, Uint(UintTy::U8)); -table.insert(sym::u16, Uint(UintTy::U16)); -table.insert(sym::u32, Uint(UintTy::U32)); -table.insert(sym::u64, Uint(UintTy::U64)); -table.insert(sym::u128, Uint(UintTy::U128)); -Self { primitive_types: table } -} -}</programlisting> -<simpara>これは初めに列挙したプリミティブ型の一覧と一致している。doc comment -にも、</simpara> -<blockquote> - <simpara>All other types are defined somewhere and possibly imported, but the - primitive ones need special handling, since they have no place of - origin.</simpara> -</blockquote> -<simpara>とある。次はこの struct -の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。</simpara> -<programlisting language="rust" linenumbering="unnumbered"> /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. -/// (略) -fn resolve_ident_in_lexical_scope( -&mut self, -mut ident: Ident, -ns: Namespace, -// (略) -) -> Option<LexicalScopeBinding<'a>> { -// (略) + table.insert(sym::bool, Bool); + table.insert(sym::char, Char); + table.insert(sym::f32, Float(FloatTy::F32)); + table.insert(sym::f64, Float(FloatTy::F64)); + table.insert(sym::isize, Int(IntTy::Isize)); + table.insert(sym::i8, Int(IntTy::I8)); + table.insert(sym::i16, Int(IntTy::I16)); + table.insert(sym::i32, Int(IntTy::I32)); + table.insert(sym::i64, Int(IntTy::I64)); + table.insert(sym::i128, Int(IntTy::I128)); + table.insert(sym::str, Str); + table.insert(sym::usize, Uint(UintTy::Usize)); + table.insert(sym::u8, Uint(UintTy::U8)); + table.insert(sym::u16, Uint(UintTy::U16)); + table.insert(sym::u32, Uint(UintTy::U32)); + table.insert(sym::u64, Uint(UintTy::U64)); + table.insert(sym::u128, Uint(UintTy::U128)); + Self { primitive_types: table } + } + } + ]]> + </programlisting> + <simpara> + これは初めに列挙したプリミティブ型の一覧と一致している。doc comment + にも、 + </simpara> + <blockquote> + <simpara> + All other types are defined somewhere and possibly imported, but the + primitive ones need special handling, since they have no place of + origin. + </simpara> + </blockquote> + <simpara> + とある。次はこの struct + の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。 + </simpara> + <programlisting language="rust" linenumbering="unnumbered"> + <![CDATA[ + /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. + /// (略) + fn resolve_ident_in_lexical_scope( + &mut self, + mut ident: Ident, + ns: Namespace, + // (略) + ) -> Option<LexicalScopeBinding<'a>> { + // (略) -if ns == TypeNS { -if let Some(prim_ty) = self.primitive_type_table.primitive_types.get(&ident.name) { -let binding = -(Res::PrimTy(*prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root()) -.to_name_binding(self.arenas); -return Some(LexicalScopeBinding::Item(binding)); -} -} + if ns == TypeNS { + if let Some(prim_ty) = self.primitive_type_table.primitive_types.get(&ident.name) { + let binding = + (Res::PrimTy(*prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root()) + .to_name_binding(self.arenas); + return Some(LexicalScopeBinding::Item(binding)); + } + } -None -}</programlisting> -<simpara>関数名や doc comment が示している通り、この関数は識別子 (identifier, -ident) を現在のレキシカルスコープ内で解決 (resolve) する。 -<literal>if ns == TypeNS</literal> のブロック内では、<literal>primitive_type_table</literal> (上記の -<literal>PrimitiveTypeTable::new()</literal> で作られた変数) に含まれている識別子 -(<literal>bool</literal>、<literal>i32</literal> など) -かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。</simpara> -<simpara>なお、<literal>ns</literal> は「名前空間」を示す変数である。Rust -における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この -<literal>if</literal> -は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。</simpara> -<simpara>重要なのは、これが <literal>resolve_ident_in_lexical_scope()</literal> - の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。</simpara> -<simpara>動作がわかったところで、例として次のコードを考える。</simpara> -<programlisting language="rust" linenumbering="unnumbered">#![allow(non_camel_case_types)] + None + } + ]]> + </programlisting> + <simpara> + 関数名や doc comment が示している通り、この関数は識別子 (identifier, + ident) を現在のレキシカルスコープ内で解決 (resolve) する。 + <literal>if ns == TypeNS</literal> のブロック内では、<literal>primitive_type_table</literal> (上記の + <literal>PrimitiveTypeTable::new()</literal> で作られた変数) に含まれている識別子 + (<literal>bool</literal>、<literal>i32</literal> など) + かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。 + </simpara> + <simpara> + なお、<literal>ns</literal> は「名前空間」を示す変数である。Rust + における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この + <literal>if</literal> + は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。 + </simpara> + <simpara> + 重要なのは、これが <literal>resolve_ident_in_lexical_scope()</literal> + の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。 + </simpara> + <simpara> + 動作がわかったところで、例として次のコードを考える。 + </simpara> + <programlisting language="rust" linenumbering="unnumbered"> + <![CDATA[ + #![allow(non_camel_case_types)] -struct bool; + struct bool; -fn main() { -let _: bool = bool; -}</programlisting> -<simpara>ここで <literal>main()</literal> の <literal>bool</literal> は <literal>struct bool</literal> - として解決される。なぜなら、プリミティブ型の判定をする前に <literal>bool</literal> - という名前の別の型が見つかるからだ。</simpara> -</section> -<section xml:id="_まとめ"> - <title>まとめ</title> - <simpara>Rust - のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。</simpara> -</section> + fn main() { + let _: bool = bool; + } + ]]> + </programlisting> + <simpara> + ここで <literal>main()</literal> の <literal>bool</literal> は <literal>struct bool</literal> + として解決される。なぜなら、プリミティブ型の判定をする前に <literal>bool</literal> + という名前の別の型が見つかるからだ。 + </simpara> + </section> + <section xml:id="_まとめ"> + <title>まとめ</title> + <simpara> + Rust + のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。 + </simpara> + </section> </article> diff --git a/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.xml b/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.xml index dc3843b..2a61fb4 100644 --- a/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.xml +++ b/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.xml @@ -15,102 +15,155 @@ </revision> </revhistory> </info> - <simpara>この記事は Qiita から移植してきたものです。 元 URL: - <link xl:href="https://qiita.com/nsfisis/items/79ab4db8564032de0b25">https://qiita.com/nsfisis/items/79ab4db8564032de0b25</link></simpara> -<simpara><hr/></simpara> -<section xml:id="_tl_dr"> - <title>TL; DR</title> - <simpara>違いはない。ただのエイリアス。</simpara> -</section> -<section xml:id="_調査記録"> - <title>調査記録</title> - <simpara>Vim の autocmd events には似通った名前のものがいくつかある。大抵は - <literal>:help</literal> - に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。</simpara> -<itemizedlist> - <listitem><literal>BufRead</literal>/<literal>BufReadPost</literal></listitem> - <listitem><literal>BufWrite</literal>/<literal>BufWritePre</literal></listitem> - <listitem><literal>BufAdd</literal>/<literal>BufCreate</literal></listitem> -</itemizedlist> -<simpara>このうち、<literal>BufAdd</literal>/<literal>BufCreate</literal> に関しては、<literal>:help BufCreate</literal> に</simpara> -<blockquote> - <simpara>The BufCreate event is for historic reasons.</simpara> -</blockquote> -<simpara>とあり、おそらくは <literal>BufAdd</literal> - のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため - vim と neovim のソースコードを調査した。</simpara> -<blockquote> - <simpara>ソースコードへのリンク - <link xl:href="https://github.com/vim/vim/tree/8e6be34338f13a6a625f19bcef82019c9adc65f2">vim - (調査時点での master branch)</link> -<link xl:href="https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3">neovim -(上に同じ)</link></simpara> + <simpara> + この記事は Qiita から移植してきたものです。 元 URL: + <link xl:href="https://qiita.com/nsfisis/items/79ab4db8564032de0b25">https://qiita.com/nsfisis/items/79ab4db8564032de0b25</link> + </simpara> + <simpara> + <hr/> + </simpara> + <section xml:id="_tl_dr"> + <title>TL; DR</title> + <simpara> + 違いはない。ただのエイリアス。 + </simpara> + </section> + <section xml:id="_調査記録"> + <title>調査記録</title> + <simpara> + Vim の autocmd events には似通った名前のものがいくつかある。大抵は + <literal>:help</literal> + に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。 + </simpara> + <itemizedlist> + <listitem><literal>BufRead</literal>/<literal>BufReadPost</literal></listitem> + <listitem><literal>BufWrite</literal>/<literal>BufWritePre</literal></listitem> + <listitem><literal>BufAdd</literal>/<literal>BufCreate</literal></listitem> + </itemizedlist> + <simpara> + このうち、<literal>BufAdd</literal>/<literal>BufCreate</literal> に関しては、<literal>:help BufCreate</literal> に + </simpara> + <blockquote> + <simpara> + The BufCreate event is for historic reasons. + </simpara> + </blockquote> + <simpara> + とあり、おそらくは <literal>BufAdd</literal> + のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため + vim と neovim のソースコードを調査した。 + </simpara> + <blockquote> + <simpara> + ソースコードへのリンク + <link xl:href="https://github.com/vim/vim/tree/8e6be34338f13a6a625f19bcef82019c9adc65f2">vim + (調査時点での master branch)</link> + <link xl:href="https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3">neovim + (上に同じ)</link> + </simpara> </blockquote> <section xml:id="_vim_のソースコード"> <title>vim のソースコード</title> - <simpara>以下は、autocmd events - の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。</simpara> -<simpara><link xl: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</link></simpara> -<programlisting language="c" linenumbering="unnumbered"> {"BufAdd", EVENT_BUFADD}, -{"BufCreate", EVENT_BUFADD},</programlisting> -<simpara><link xl: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</link></simpara> -<programlisting language="c" linenumbering="unnumbered"> {"BufRead", EVENT_BUFREADPOST}, -{"BufReadCmd", EVENT_BUFREADCMD}, -{"BufReadPost", EVENT_BUFREADPOST},</programlisting> -<simpara><link xl: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</link></simpara> -<programlisting language="c" linenumbering="unnumbered"> {"BufWrite", EVENT_BUFWRITEPRE}, -{"BufWritePost", EVENT_BUFWRITEPOST}, -{"BufWritePre", EVENT_BUFWRITEPRE},</programlisting> + <simpara> + 以下は、autocmd events + の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。 + </simpara> + <simpara> + <link xl: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</link> + </simpara> + <programlisting language="c" linenumbering="unnumbered"> + <![CDATA[ + {"BufAdd", EVENT_BUFADD}, + {"BufCreate", EVENT_BUFADD}, + ]]> + </programlisting> + <simpara> + <link xl: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</link> + </simpara> + <programlisting language="c" linenumbering="unnumbered"> + <![CDATA[ + {"BufRead", EVENT_BUFREADPOST}, + {"BufReadCmd", EVENT_BUFREADCMD}, + {"BufReadPost", EVENT_BUFREADPOST}, + ]]> + </programlisting> + <simpara> + <link xl: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</link> + </simpara> + <programlisting language="c" linenumbering="unnumbered"> + <![CDATA[ + {"BufWrite", EVENT_BUFWRITEPRE}, + {"BufWritePost", EVENT_BUFWRITEPOST}, + {"BufWritePre", EVENT_BUFWRITEPRE}, + ]]> + </programlisting> </section> <section xml:id="_neovim_のソースコード"> <title>neovim のソースコード</title> - <simpara>neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua - で書かれている。以下にある通り、はっきり <literal>aliases</literal> と書かれている。</simpara> -<simpara><link xl: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</link></simpara> -<programlisting language="lua" linenumbering="unnumbered"> aliases = { -BufCreate = 'BufAdd', -BufRead = 'BufReadPost', -BufWrite = 'BufWritePre', -FileEncoding = 'EncodingChanged', -},</programlisting> -<simpara>ところで、上では取り上げなかった <literal>FileEncoding</literal> だが、これは -<literal>:help FileEncoding</literal> にしっかりと書いてある。</simpara> -<literallayout class="monospaced"> *FileEncoding* -FileEncoding Obsolete. It still works and is equivalent -to |EncodingChanged|.</literallayout> + <simpara> + neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua + で書かれている。以下にある通り、はっきり <literal>aliases</literal> と書かれている。 + </simpara> + <simpara> + <link xl: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</link> + </simpara> + <programlisting language="lua" linenumbering="unnumbered"> + <![CDATA[ + aliases = { + BufCreate = 'BufAdd', + BufRead = 'BufReadPost', + BufWrite = 'BufWritePre', + FileEncoding = 'EncodingChanged', + }, + ]]> + </programlisting> + <simpara> + ところで、上では取り上げなかった <literal>FileEncoding</literal> だが、これは + <literal>:help FileEncoding</literal> にしっかりと書いてある。 + </simpara> + <literallayout class="monospaced"> *FileEncoding* + <![CDATA[ + FileEncoding Obsolete. It still works and is equivalent + to |EncodingChanged|. + ]]> +</literallayout> </section> <section xml:id="_まとめ"> <title>まとめ</title> - <simpara>記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。</simpara> + <simpara> + 記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。 + </simpara> <itemizedlist> <listitem> <literal>BufAdd</literal>/<literal>BufCreate</literal> <itemizedlist> <listitem>→ <literal>BufCreate</literal> は歴史的な理由により ("for historic reasons") 存在しているため、新しい方 (<literal>BufAdd</literal>) を使う</listitem> + </itemizedlist> + </listitem> + <listitem> + <literal>BufRead</literal>/<literal>BufReadPost</literal> + <itemizedlist> + <listitem>→ <literal>BufReadPre</literal> との対称性のため、あるいは <literal>BufWritePost</literal> との対称性のため <literal>BufReadPost</literal> を使う</listitem> + </itemizedlist> + </listitem> + <listitem> + <literal>BufWrite</literal>/<literal>BufWritePre</literal> + <itemizedlist> + <listitem>→ <literal>BufWritePost</literal> との対称性のため、あるいは <literal>BufReadPre</literal> との対称性のため <literal>BufWritePre</literal> を使う</listitem> + </itemizedlist> + </listitem> + <listitem> + <literal>FileEncoding</literal>/<literal>EncodingChanged</literal> + <itemizedlist> + <listitem>→ <literal>FileEncoding</literal> は <literal>`Obsolete'' と明言されているので、`EncodingChanged</literal> を使う</listitem> + </itemizedlist> + </listitem> </itemizedlist> -</listitem> -<listitem> - <literal>BufRead</literal>/<literal>BufReadPost</literal> - <itemizedlist> - <listitem>→ <literal>BufReadPre</literal> との対称性のため、あるいは <literal>BufWritePost</literal> との対称性のため <literal>BufReadPost</literal> を使う</listitem> - </itemizedlist> -</listitem> -<listitem> - <literal>BufWrite</literal>/<literal>BufWritePre</literal> - <itemizedlist> - <listitem>→ <literal>BufWritePost</literal> との対称性のため、あるいは <literal>BufReadPre</literal> との対称性のため <literal>BufWritePre</literal> を使う</listitem> - </itemizedlist> -</listitem> -<listitem> - <literal>FileEncoding</literal>/<literal>EncodingChanged</literal> - <itemizedlist> - <listitem>→ <literal>FileEncoding</literal> は <literal>`Obsolete'' と明言されているので、`EncodingChanged</literal> を使う</listitem> -</itemizedlist> -</listitem> -</itemizedlist> -<simpara>ところでこの調査で知ったのだが、<literal>BufRead</literal> と <literal>BufWrite</literal> - は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら - <literal>Pre</literal>/<literal>Post</literal> 付きのものを使った方が分かりやすいだろう。</simpara> + <simpara> + ところでこの調査で知ったのだが、<literal>BufRead</literal> と <literal>BufWrite</literal> + は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら + <literal>Pre</literal>/<literal>Post</literal> 付きのものを使った方が分かりやすいだろう。 + </simpara> </section> </section> </article> diff --git a/content/posts/2021-10-02/vim-swap-order-of-selected-lines.xml b/content/posts/2021-10-02/vim-swap-order-of-selected-lines.xml index 9b7c809..f50a8a0 100644 --- a/content/posts/2021-10-02/vim-swap-order-of-selected-lines.xml +++ b/content/posts/2021-10-02/vim-swap-order-of-selected-lines.xml @@ -15,126 +15,204 @@ </revision> </revhistory> </info> - <simpara>この記事は Qiita から移植してきたものです。 元 URL: - <link xl:href="https://qiita.com/nsfisis/items/4fefb361d9a693803520">https://qiita.com/nsfisis/items/4fefb361d9a693803520</link></simpara> -<simpara><hr/></simpara> -<section xml:id="_バージョン情報"> - <title>バージョン情報</title> - <simpara><literal>:version</literal> の一部</simpara> - <blockquote> - <simpara>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.</simpara> -</blockquote> -</section> -<section xml:id="_よく紹介されている手法"> - <title>よく紹介されている手法</title> - <section xml:id="_tac_tail"> - <title><literal>tac</literal> / <literal>tail</literal></title> - <simpara><literal>tac</literal> や <literal>tail -r</literal> などの外部コマンドを <literal>!</literal> - を使って呼び出し、置き換える。</simpara> + <simpara> + この記事は Qiita から移植してきたものです。 元 URL: + <link xl:href="https://qiita.com/nsfisis/items/4fefb361d9a693803520">https://qiita.com/nsfisis/items/4fefb361d9a693803520</link> + </simpara> + <simpara> + <hr/> + </simpara> + <section xml:id="_バージョン情報"> + <title>バージョン情報</title> + <simpara> + <literal>:version</literal> の一部 + </simpara> <blockquote> - <simpara>:h v_!</simpara> + <simpara> + 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. + </simpara> </blockquote> - <simpara><literal>tac</literal> コマンドや <literal>tail</literal> の <literal>-r</literal> - オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい</simpara> </section> - <section xml:id="_gm0"> - <title><literal>:g/^/m0</literal></title> - <simpara>こちらは外部コマンドに頼らず、Vim の機能のみを使う。<literal>g</literal> は <literal>:global</literal> - コマンドの、<literal>m</literal> は <literal>:move</literal> コマンドの略</simpara> - <simpara><literal>:global</literal> コマンドは <literal>:[range]global/{pattern}/[command]</literal> - のように使い、<literal>[range]</literal> で指定された範囲の行のうち、<literal>{pattern}</literal> - で指定された検索パターンにマッチする行に対して、順番に <literal>[command]</literal> - で指定された Ex コマンドを呼び出す。</simpara> + <section xml:id="_よく紹介されている手法"> + <title>よく紹介されている手法</title> + <section xml:id="_tac_tail"> + <title><literal>tac</literal> / <literal>tail</literal></title> + <simpara> + <literal>tac</literal> や <literal>tail -r</literal> などの外部コマンドを <literal>!</literal> + を使って呼び出し、置き換える。 + </simpara> + <blockquote> + <simpara> + :h v_! + </simpara> + </blockquote> + <simpara> + <literal>tac</literal> コマンドや <literal>tail</literal> の <literal>-r</literal> + オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい + </simpara> + </section> + <section xml:id="_gm0"> + <title><literal>:g/^/m0</literal></title> + <simpara> + こちらは外部コマンドに頼らず、Vim の機能のみを使う。<literal>g</literal> は <literal>:global</literal> + コマンドの、<literal>m</literal> は <literal>:move</literal> コマンドの略 + </simpara> + <simpara> + <literal>:global</literal> コマンドは <literal>:[range]global/{pattern}/[command]</literal> + のように使い、<literal>[range]</literal> で指定された範囲の行のうち、<literal>{pattern}</literal> + で指定された検索パターンにマッチする行に対して、順番に <literal>[command]</literal> + で指定された Ex コマンドを呼び出す。 + </simpara> + <blockquote> + <simpara> + :h :global + </simpara> + </blockquote> + <simpara> + <literal>:move</literal> コマンドは <literal>[range]:move {address}</literal> のように使い、<literal>[range]</literal> + で指定された範囲の行を <literal>{address}</literal> で指定された位置に移動させる。 + </simpara> + <blockquote> + <simpara> + :h :move + </simpara> + </blockquote> + <simpara> + <literal>:g/^/m0</literal> のように組み合わせると、「すべての行を1行ずつ + 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。 + </simpara> + <simpara> + なお、<literal>:g/^/m0</literal> は全ての行を入れ替えるが、<literal>:N,Mg/^/mN-1</literal> とすることで + N行目から + M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。 + </simpara> + <programlisting language="vim" linenumbering="unnumbered"> + <![CDATA[ + command! -bar -range=% + \ Reverse + \ <line1>,<line2>g/^/m<line1>-1 + ]]> + </programlisting> + <simpara> + これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。 + </simpara> + </section> + </section> + <section xml:id="_gm0_の問題点"> + <title><literal>:g/^/m0</literal> の問題点</title> + <simpara> + <literal>:global</literal> + コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。<literal>^</literal> + は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。<literal>'hlsearch'</literal> + オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと + <literal>n</literal> コマンドなどの際に不便である。 + </simpara> <blockquote> - <simpara>:h :global</simpara> + <simpara> + :h @/ + </simpara> </blockquote> - <simpara><literal>:move</literal> コマンドは <literal>[range]:move {address}</literal> のように使い、<literal>[range]</literal> - で指定された範囲の行を <literal>{address}</literal> で指定された位置に移動させる。</simpara> + </section> + <section xml:id="_解決策"> + <title>解決策</title> <blockquote> - <simpara>:h :move</simpara> + <simpara> + [2020/9/28追記] より簡潔な方法を見つけたので次節に追記した + </simpara> </blockquote> - <simpara><literal>:g/^/m0</literal> のように組み合わせると、「すべての行を1行ずつ - 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。</simpara> - <simpara>なお、<literal>:g/^/m0</literal> は全ての行を入れ替えるが、<literal>:N,Mg/^/mN-1</literal> とすることで - N行目から - M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。</simpara> -<programlisting language="vim" linenumbering="unnumbered">command! -bar -range=% -\ Reverse -\ <line1>,<line2>g/^/m<line1>-1</programlisting> -<simpara>これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。</simpara> -</section> -</section> -<section xml:id="_gm0_の問題点"> - <title><literal>:g/^/m0</literal> の問題点</title> - <simpara><literal>:global</literal> - コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。<literal>^</literal> - は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。<literal>'hlsearch'</literal> - オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと - <literal>n</literal> コマンドなどの際に不便である。</simpara> - <blockquote> - <simpara>:h @/</simpara> - </blockquote> -</section> -<section xml:id="_解決策"> - <title>解決策</title> - <blockquote> - <simpara>[2020/9/28追記] より簡潔な方法を見つけたので次節に追記した</simpara> - </blockquote> - <simpara>前述した <literal>:Reverse</literal> コマンドの定義を少し変えて、次のようにする:</simpara> - <programlisting language="vim" linenumbering="unnumbered">function! s:reverse_lines(from, to) abort - execute printf("%d,%dg/^/m%d", a:from, a:to, a:from - 1) - endfunction + <simpara> + 前述した <literal>:Reverse</literal> コマンドの定義を少し変えて、次のようにする: + </simpara> + <programlisting language="vim" linenumbering="unnumbered"> + <![CDATA[ + function! s:reverse_lines(from, to) abort + execute printf("%d,%dg/^/m%d", a:from, a:to, a:from - 1) + endfunction - command! -bar -range=% - \ Reverse - \ call <SID>reverse_lines(<line1>, <line2>)</programlisting> -<simpara>実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。</simpara> -<simpara>この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが -<literal>^</literal> で上書きされることがなくなる。</simpara> -<simpara>Vim のヘルプから該当箇所を引用する (強調は筆者による)。</simpara> -<blockquote> - <simpara>:h autocmd-searchpat</simpara> - <simpara><emphasis role="strong">Autocommands do not change the current search patterns.</emphasis> 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' option.</simpara> -</blockquote> -<simpara>これは autocommand -の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは -<literal>:nohlsearch</literal> のヘルプにある。同じく該当箇所を引用する -(強調は筆者による)。</simpara> -<blockquote> - <simpara>:h :nohlsearch</simpara> - <simpara>(略) This command doesn’t work in an autocommand, because the - highlighting state is saved and restored when executing autocommands - |autocmd-searchpat|. <emphasis role="strong">Same thing for when invoking a user function.</emphasis></simpara> -</blockquote> -<simpara>この仕様により、<literal>:g/^/m0</literal> - の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。</simpara> -</section> -<section xml:id="_解決策_改訂版"> - <title>解決策 (改訂版)</title> - <blockquote> - <simpara>[2020/9/28追記] より簡潔な方法を見つけたため追記する</simpara> - </blockquote> - <programlisting language="vim" linenumbering="unnumbered">command! -bar -range=% - \ Reverse - \ keeppatterns <line1>,<line2>g/^/m<line1>-1</programlisting> -<simpara>まさにこのための Exコマンド、<literal>:keeppatterns</literal> - が存在する。<literal>:keeppatterns {command}</literal> - のように使い、読んで字の如く、後ろに続く - Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。</simpara> -<blockquote> - <simpara>:h :keeppatterns</simpara> -</blockquote> -</section> -<section xml:id="_コピペ用再掲"> - <title>コピペ用再掲</title> - <programlisting language="vim" linenumbering="unnumbered">" License: Public Domain + command! -bar -range=% + \ Reverse + \ call <SID>reverse_lines(<line1>, <line2>) + ]]> + </programlisting> + <simpara> + 実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。 + </simpara> + <simpara> + この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが + <literal>^</literal> で上書きされることがなくなる。 + </simpara> + <simpara> + Vim のヘルプから該当箇所を引用する (強調は筆者による)。 + </simpara> + <blockquote> + <simpara> + :h autocmd-searchpat + </simpara> + <simpara> + <emphasis role="strong">Autocommands do not change the current search patterns.</emphasis> 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' option. + </simpara> + </blockquote> + <simpara> + これは autocommand + の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは + <literal>:nohlsearch</literal> のヘルプにある。同じく該当箇所を引用する + (強調は筆者による)。 + </simpara> + <blockquote> + <simpara> + :h :nohlsearch + </simpara> + <simpara> + (略) This command doesn’t work in an autocommand, because the + highlighting state is saved and restored when executing autocommands + |autocmd-searchpat|. <emphasis role="strong">Same thing for when invoking a user function.</emphasis> + </simpara> + </blockquote> + <simpara> + この仕様により、<literal>:g/^/m0</literal> + の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。 + </simpara> + </section> + <section xml:id="_解決策_改訂版"> + <title>解決策 (改訂版)</title> + <blockquote> + <simpara> + [2020/9/28追記] より簡潔な方法を見つけたため追記する + </simpara> + </blockquote> + <programlisting language="vim" linenumbering="unnumbered"> + <![CDATA[ + command! -bar -range=% + \ Reverse + \ keeppatterns <line1>,<line2>g/^/m<line1>-1 + ]]> + </programlisting> + <simpara> + まさにこのための Exコマンド、<literal>:keeppatterns</literal> + が存在する。<literal>:keeppatterns {command}</literal> + のように使い、読んで字の如く、後ろに続く + Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。 + </simpara> + <blockquote> + <simpara> + :h :keeppatterns + </simpara> + </blockquote> + </section> + <section xml:id="_コピペ用再掲"> + <title>コピペ用再掲</title> + <programlisting language="vim" linenumbering="unnumbered"> + <![CDATA[ + " License: Public Domain - command! -bar -range=% - \ Reverse - \ keeppatterns <line1>,<line2>g/^/m<line1>-1</programlisting> -</section> + command! -bar -range=% + \ Reverse + \ keeppatterns <line1>,<line2>g/^/m<line1>-1 + ]]> + </programlisting> + </section> </article> diff --git a/content/posts/2022-04-09/phperkaigi-2022-tokens.xml b/content/posts/2022-04-09/phperkaigi-2022-tokens.xml index 0f5d7be..e3d9c45 100644 --- a/content/posts/2022-04-09/phperkaigi-2022-tokens.xml +++ b/content/posts/2022-04-09/phperkaigi-2022-tokens.xml @@ -21,381 +21,543 @@ </revision> </revhistory> </info> - <section xml:id="_はじめに"> + <section xml:id="intro"> <title>はじめに</title> - <simpara>本日開始された <link xl:href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</link> の PHPer - チャレンジにおいて、弊社 - <link xl:href="https://www.dgcircus.com/">デジタルサーカス株式会社</link> の問題を - 3問作成した。この記事では、これらの問題の解説をおこなう。</simpara> - <simpara>リポジトリはこちら: <link xl:href="https://github.com/nsfisis/PHPerKaigi2022-tokens">https://github.com/nsfisis/PHPerKaigi2022-tokens</link></simpara> -</section> -<section xml:id="_第1問_brainf_ck_php"> - <title>第1問 brainf_ck.php</title> - <simpara>ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。</simpara> - <programlisting language="php" linenumbering="unnumbered"><?php + <simpara> + 本日開始された <link xl:href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</link> の PHPer + チャレンジにおいて、弊社 + <link xl:href="https://www.dgcircus.com/">デジタルサーカス株式会社</link> の問題を + 3問作成した。この記事では、これらの問題の解説をおこなう。 + </simpara> + <simpara> + リポジトリはこちら: <link xl:href="https://github.com/nsfisis/PHPerKaigi2022-tokens">https://github.com/nsfisis/PHPerKaigi2022-tokens</link> + </simpara> + </section> + <section xml:id="_第1問_brainf_ck_php"> + <title>第1問 brainf_ck.php</title> + <simpara> + ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + <?php - declare(strict_types=0O1); + declare(strict_types=0O1); - namespace Dgcircus\PHPerKaigi\Y2022; + namespace Dgcircus\PHPerKaigi\Y2022; - /** - * @todo - * Run this program to acquire a PHPer token. - */ + /** + * @todo + * Run this program to acquire a PHPer token. + */ - https://creativecommons.org/publicdomain/zero/1.0/ + https://creativecommons.org/publicdomain/zero/1.0/ - \error_reporting(~+!'We are hiring!'); + \error_reporting(~+!'We are hiring!'); - $z = fn($f) => (fn($x) => $f(fn(...$xs) => $x($x)(...$xs)))(fn($x) => $f(fn(...$xs) => $x($x)(...$xs))); - $id = \spl_object_id(...); - $put = fn($c) => \printf('%c', $c); - $mm = fn($p, $n) => new \ArrayObject(\array_fill(+!![], $n, $p)); + $z = fn($f) => (fn($x) => $f(fn(...$xs) => $x($x)(...$xs)))(fn($x) => $f(fn(...$xs) => $x($x)(...$xs))); + $id = \spl_object_id(...); + $put = fn($c) => \printf('%c', $c); + $mm = fn($p, $n) => new \ArrayObject(\array_fill(+!![], $n, $p)); - $👉 = fn($m, $p, $b, $e, $mp, $pc) => [++$mp, ++$pc]; - $👈 = fn($m, $p, $b, $e, $mp, $pc) => [--$mp, ++$pc]; - $👍 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, ++$m[$mp]]; - $👎 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, --$m[$mp]]; - $📝 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, $put($m[$mp])]; - $🤡 = fn($m, $p, $b, $e, $mp, $pc) => match ($m[$mp]) { - +!![] => [$mp, $z(fn($loop) => fn($pc, $n) => match ($id($p[$pc])) { - $b => $loop(++$pc, ++$n), - $e => $n === +!![] ? ++$pc : $loop(++$pc, --$n), - default => $loop(++$pc, $n), - })($pc, -![])], - default => [$mp, ++$pc], - }; - $🎪 = fn($m, $p, $b, $e, $mp, $pc) => match ($m[$mp]) { - +!![] => [$mp, ++$pc], - default => [$mp, $z(fn($loop) => fn($pc, $n) => match ($id($p[$pc])) { - $e => $loop(--$pc, ++$n), - $b => $n === +!![] ? $pc+![] : $loop(--$pc, --$n), - default => $loop(--$pc, $n), - })($pc, -![])], - }; - $🐘 = fn($p) => $z(fn($loop) => fn($m, $p, $b, $e, $mp, $pc) => - isset($p[$pc]) && $loop($m, $p, $b, $e, ...($p[$pc]($m, $p, $b, $e, $mp, $pc))) - )($mm(+!![], +(![].![])), $p, $id($🤡), $id($🎪), +!![], +!![]); + $👉 = fn($m, $p, $b, $e, $mp, $pc) => [++$mp, ++$pc]; + $👈 = fn($m, $p, $b, $e, $mp, $pc) => [--$mp, ++$pc]; + $👍 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, ++$m[$mp]]; + $👎 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, --$m[$mp]]; + $📝 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, $put($m[$mp])]; + $🤡 = fn($m, $p, $b, $e, $mp, $pc) => match ($m[$mp]) { + +!![] => [$mp, $z(fn($loop) => fn($pc, $n) => match ($id($p[$pc])) { + $b => $loop(++$pc, ++$n), + $e => $n === +!![] ? ++$pc : $loop(++$pc, --$n), + default => $loop(++$pc, $n), + })($pc, -![])], + default => [$mp, ++$pc], + }; + $🎪 = fn($m, $p, $b, $e, $mp, $pc) => match ($m[$mp]) { + +!![] => [$mp, ++$pc], + default => [$mp, $z(fn($loop) => fn($pc, $n) => match ($id($p[$pc])) { + $e => $loop(--$pc, ++$n), + $b => $n === +!![] ? $pc+![] : $loop(--$pc, --$n), + default => $loop(--$pc, $n), + })($pc, -![])], + }; + $🐘 = fn($p) => $z(fn($loop) => fn($m, $p, $b, $e, $mp, $pc) => + isset($p[$pc]) && $loop($m, $p, $b, $e, ...($p[$pc]($m, $p, $b, $e, $mp, $pc))) + )($mm(+!![], +(![].![])), $p, $id($🤡), $id($🎪), +!![], +!![]); - $🐘([ - $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, - $🤡, - $👉, $👍, $👍, $👍, - $👉, $👍, $👍, $👍, $👍, $👍, - $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, - $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, - $👈, $👈, $👈, $👈, $👎, - $🎪, - $👉, $👍, $👍, $👍, $👍, $👍, $📝, - $👎, $👎, $📝, - $👉, $👎, $👎, $👎, $📝, - $👉, $👎, $👎, $👎, $📝, - $👎, $👎, $📝, - $👎, $📝, - $👈, $📝, - $👉, $👉, $👎, $👎, $📝, - $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝, - $👈, $👎, $👎, $👎, $👎, $📝, - $👈, $📝, - $👉, $👍, $👍, $📝, - $👉, $👎, $📝, - $👈, $📝, - ]);</programlisting> -<simpara>この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。</simpara> -<section xml:id="_解説"> - <title>解説</title> - <section xml:id="_絵文字"> - <title>絵文字</title> - <simpara>まず目につくのは大量の絵文字だろう。 PHP - は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。</simpara> -</section> -<section xml:id="_プログラム全体"> - <title>プログラム全体</title> - <simpara>Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck - とは、難解プログラミング言語のひとつであり、ここで説明するよりも - Wikipedia の該当ページを読んだ方がよい。</simpara> -<simpara><link xl:href="https://ja.wikipedia.org/wiki/Brainfuck">https://ja.wikipedia.org/wiki/Brainfuck</link></simpara> -<simpara>なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。</simpara> -<literallayout class="monospaced">+ + + + + + + + + + -[ -> + + + -> + + + + + -> + + + + + + + + + + + + -> + + + + + + + + + + -< < < < - -] -> + + + + + . -- - . -> - - - . -> - - - . -- - . -- . -< . -> > - - . -+ + + + + + + . -< - - - - . -< . -> + + . -> - . -< .</literallayout> -<simpara>実行結果はこちら: <link xl:href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</link></simpara> -<simpara>それぞれの絵文字で表された関数が、各命令に対応している。</simpara> -<itemizedlist> - <listitem><literal>$👉</literal>: <literal>></literal></listitem> - <listitem><literal>$👈</literal>: <literal><</literal></listitem> - <listitem><literal>$👍</literal>: <literal>+</literal></listitem> - <listitem><literal>$👎</literal>: <literal>-</literal></listitem> - <listitem><literal>$📝</literal>: <literal>.</literal></listitem> - <listitem><literal>$🤡</literal>: <literal>[</literal></listitem> - <listitem><literal>$🎪</literal>: <literal>]</literal></listitem> -</itemizedlist> -<simpara><literal>,</literal> (入力) に対応する関数はない -(このプログラムでは使わないので用意していない)。</simpara> -<simpara>なお、<literal>$🐘</literal> はいわゆる main 関数であり、プログラムの実行部分である。</simpara> -</section> -<section xml:id="_絵文字の選択"> - <title>絵文字の選択</title> - <simpara>おおよそ意味に合致するよう選んでいるが、<literal>$🤡</literal> と <literal>$🎪</literal> - は弊社デジタルサーカスにちなんでいる。 また、<literal>$🐘</literal> は PHP - のマスコットの象に由来する。</simpara> -</section> -<section xml:id="_strict_types"> - <title>strict_types</title> - <simpara><literal>declare</literal> 文の <literal>strict_types</literal> に指定できるのは、<literal>0</literal> か <literal>1</literal> - の数値リテラルだが、 <literal>0x0</literal> や <literal>0b1</literal> のような値も受け付ける。 今回は、PHP - 8.1 から追加された、<literal>0O</literal> または <literal>0o</literal> から始まる八進数リテラルを使った。</simpara> -</section> -<section xml:id="_url"> - <title>URL</title> - <simpara>ソースコードのライセンスを示したこの部分だが、</simpara> - <programlisting language="php" linenumbering="unnumbered">https://creativecommons.org/publicdomain/zero/1.0/</programlisting> - <simpara>完全に合法な PHP のコードである。 <literal>https:</literal> 部分はラベル、<literal>//</literal> - 以降は行コメントになっている。</simpara> -</section> -<section xml:id="_リテラルなしで数値を生成する"> - <title>リテラルなしで数値を生成する</title> - <simpara>ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 - PHP では、型変換を利用することで任意の整数を作り出すことができる。</simpara> -<programlisting language="php" linenumbering="unnumbered">assert(0 === +!![]); -assert(1 === +![]); -assert(2 === ![]+![]); -assert(3 === ![]+![]+![]); -assert(10 === +(![].+!![]));</programlisting> -<simpara><literal>[]</literal> に <literal>!</literal> を適用すると <literal>true</literal> が返ってくる。それに <literal>+</literal> - を適用すると、<literal>bool</literal> から <literal>int</literal> ヘの型変換が走り、<literal>1</literal> が生成される。<literal>10</literal> - はさらにトリッキーだ。まず <literal>1</literal> と <literal>0</literal> を作り、<literal>.</literal> で文字列として結合する - (<literal>'10'</literal>)。これに <literal>+</literal> を適用すると、<literal>string</literal> から <literal>int</literal> - への型変換が走り、<literal>10</literal> が生まれる (コード量に頓着しないなら、<literal>1</literal> を 10 - 個足し合わせてももちろん 10 が作れる)。</simpara> -<simpara>また、<literal>error_reporting</literal> に指定しているのは <literal>-1</literal> である。 これは、<literal>!</literal> - によって文字列を <literal>false</literal> にし、<literal>+</literal> によって <literal>false</literal> を <literal>0</literal> - にし、さらにビット反転して <literal>-1</literal> にしている。</simpara> -</section> -<section xml:id="_if_文なしで条件分岐"> - <title><literal>if</literal> 文なしで条件分岐</title> - <simpara>三項演算子ないし <literal>match</literal> 式を使うことで、<literal>if</literal> - を一切書かずに条件分岐ができる。 また、<literal>&&</literal> / <literal>||</literal> も使えることがある。 - 遅延評価が不要なケースでは、<literal>[$t, $f][$cond]</literal> - のような形で分岐することもできる。</simpara> -</section> -<section xml:id="_whilefor_文なしでループ"> - <title><literal>while</literal>、<literal>for</literal> 文なしでループ</title> - <simpara>不動点コンビネータを使って無名再帰する - (詳しい説明は省略する。これらの単語で検索してほしい)。 ここでは、一般に - Z コンビネータとして知られるものを使った (<literal>$z</literal>)。</simpara> -<simpara>実際のところ、<literal>$🤡</literal> や <literal>$🎪</literal>、<literal>$🐘</literal> は、一度 Scheme (Lisp の一種) -で書いてから PHP に翻訳する形で記述した。</simpara> -<simpara>なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) -ので、 あまりに長い brainf*ck -プログラムを書くとスタックオーバーフローする。</simpara> -</section> -</section> -</section> -<section xml:id="_第2問_riddle_php"> - <title>第2問 riddle.php</title> - <simpara>ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。</simpara> - <programlisting language="php" linenumbering="unnumbered"><?php + $🐘([ + $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, + $🤡, + $👉, $👍, $👍, $👍, + $👉, $👍, $👍, $👍, $👍, $👍, + $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, + $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, + $👈, $👈, $👈, $👈, $👎, + $🎪, + $👉, $👍, $👍, $👍, $👍, $👍, $📝, + $👎, $👎, $📝, + $👉, $👎, $👎, $👎, $📝, + $👉, $👎, $👎, $👎, $📝, + $👎, $👎, $📝, + $👎, $📝, + $👈, $📝, + $👉, $👉, $👎, $👎, $📝, + $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝, + $👈, $👎, $👎, $👎, $👎, $📝, + $👈, $📝, + $👉, $👍, $👍, $📝, + $👉, $👎, $📝, + $👈, $📝, + ]); + ]]> + </programlisting> + <simpara> + この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。 + </simpara> + <section xml:id="_解説"> + <title>解説</title> + <section xml:id="_絵文字"> + <title>絵文字</title> + <simpara> + まず目につくのは大量の絵文字だろう。 PHP + は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。 + </simpara> + </section> + <section xml:id="_プログラム全体"> + <title>プログラム全体</title> + <simpara> + Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck + とは、難解プログラミング言語のひとつであり、ここで説明するよりも + Wikipedia の該当ページを読んだ方がよい。 + </simpara> + <simpara> + <link xl:href="https://ja.wikipedia.org/wiki/Brainfuck">https://ja.wikipedia.org/wiki/Brainfuck</link> + </simpara> + <simpara> + なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。 + </simpara> + <literallayout class="monospaced"> + <![CDATA[ + + + + + + + + + + + + [ + > + + + + > + + + + + + > + + + + + + + + + + + + + > + + + + + + + + + + + < < < < - + ] + > + + + + + . + - - . + > - - - . + > - - - . + - - . + - . + < . + > > - - . + + + + + + + + . + < - - - - . + < . + > + + . + > - . + < . + ]]> + </literallayout> + <simpara> + 実行結果はこちら: <link xl:href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</link> + </simpara> + <simpara> + それぞれの絵文字で表された関数が、各命令に対応している。 + </simpara> + <itemizedlist> + <listitem><literal>$👉</literal>: <literal>></literal></listitem> + <listitem><literal>$👈</literal>: <literal><</literal></listitem> + <listitem><literal>$👍</literal>: <literal>+</literal></listitem> + <listitem><literal>$👎</literal>: <literal>-</literal></listitem> + <listitem><literal>$📝</literal>: <literal>.</literal></listitem> + <listitem><literal>$🤡</literal>: <literal>[</literal></listitem> + <listitem><literal>$🎪</literal>: <literal>]</literal></listitem> + </itemizedlist> + <simpara> + <literal>,</literal> (入力) に対応する関数はない + (このプログラムでは使わないので用意していない)。 + </simpara> + <simpara> + なお、<literal>$🐘</literal> はいわゆる main 関数であり、プログラムの実行部分である。 + </simpara> + </section> + <section xml:id="_絵文字の選択"> + <title>絵文字の選択</title> + <simpara> + おおよそ意味に合致するよう選んでいるが、<literal>$🤡</literal> と <literal>$🎪</literal> + は弊社デジタルサーカスにちなんでいる。 また、<literal>$🐘</literal> は PHP + のマスコットの象に由来する。 + </simpara> + </section> + <section xml:id="_strict_types"> + <title>strict_types</title> + <simpara> + <literal>declare</literal> 文の <literal>strict_types</literal> に指定できるのは、<literal>0</literal> か <literal>1</literal> + の数値リテラルだが、 <literal>0x0</literal> や <literal>0b1</literal> のような値も受け付ける。 今回は、PHP + 8.1 から追加された、<literal>0O</literal> または <literal>0o</literal> から始まる八進数リテラルを使った。 + </simpara> + </section> + <section xml:id="_url"> + <title>URL</title> + <simpara> + ソースコードのライセンスを示したこの部分だが、 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + https://creativecommons.org/publicdomain/zero/1.0/ + ]]> + </programlisting> + <simpara> + 完全に合法な PHP のコードである。 <literal>https:</literal> 部分はラベル、<literal>//</literal> + 以降は行コメントになっている。 + </simpara> + </section> + <section xml:id="_リテラルなしで数値を生成する"> + <title>リテラルなしで数値を生成する</title> + <simpara> + ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 + PHP では、型変換を利用することで任意の整数を作り出すことができる。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + assert(0 === +!![]); + assert(1 === +![]); + assert(2 === ![]+![]); + assert(3 === ![]+![]+![]); + assert(10 === +(![].+!![])); + ]]> + </programlisting> + <simpara> + <literal>[]</literal> に <literal>!</literal> を適用すると <literal>true</literal> が返ってくる。それに <literal>+</literal> + を適用すると、<literal>bool</literal> から <literal>int</literal> ヘの型変換が走り、<literal>1</literal> が生成される。<literal>10</literal> + はさらにトリッキーだ。まず <literal>1</literal> と <literal>0</literal> を作り、<literal>.</literal> で文字列として結合する + (<literal>'10'</literal>)。これに <literal>+</literal> を適用すると、<literal>string</literal> から <literal>int</literal> + への型変換が走り、<literal>10</literal> が生まれる (コード量に頓着しないなら、<literal>1</literal> を 10 + 個足し合わせてももちろん 10 が作れる)。 + </simpara> + <simpara> + また、<literal>error_reporting</literal> に指定しているのは <literal>-1</literal> である。 これは、<literal>!</literal> + によって文字列を <literal>false</literal> にし、<literal>+</literal> によって <literal>false</literal> を <literal>0</literal> + にし、さらにビット反転して <literal>-1</literal> にしている。 + </simpara> + </section> + <section xml:id="_if_文なしで条件分岐"> + <title><literal>if</literal> 文なしで条件分岐</title> + <simpara> + 三項演算子ないし <literal>match</literal> 式を使うことで、<literal>if</literal> + を一切書かずに条件分岐ができる。 また、<literal>&&</literal> / <literal>||</literal> も使えることがある。 + 遅延評価が不要なケースでは、<literal>[$t, $f][$cond]</literal> + のような形で分岐することもできる。 + </simpara> + </section> + <section xml:id="_whilefor_文なしでループ"> + <title><literal>while</literal>、<literal>for</literal> 文なしでループ</title> + <simpara> + 不動点コンビネータを使って無名再帰する + (詳しい説明は省略する。これらの単語で検索してほしい)。 ここでは、一般に + Z コンビネータとして知られるものを使った (<literal>$z</literal>)。 + </simpara> + <simpara> + 実際のところ、<literal>$🤡</literal> や <literal>$🎪</literal>、<literal>$🐘</literal> は、一度 Scheme (Lisp の一種) + で書いてから PHP に翻訳する形で記述した。 + </simpara> + <simpara> + なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) + ので、 あまりに長い brainf*ck + プログラムを書くとスタックオーバーフローする。 + </simpara> + </section> + </section> + </section> + <section xml:id="_第2問_riddle_php"> + <title>第2問 riddle.php</title> + <simpara> + ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + <?php - /********************************************************* - * This program displays a PHPer token. * - * Guess 'N'. * - * * - * 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/ * - *********************************************************/ - const N = 0 /* Change it to your answer. */; - assert(0 <= N && N <= 0b11111_11111_11111_11111_11111); + /********************************************************* + * This program displays a PHPer token. * + * Guess 'N'. * + * * + * 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/ * + *********************************************************/ + const N = 0 /* Change it to your answer. */; + assert(0 <= N && N <= 0b11111_11111_11111_11111_11111); - $token = [ - 0x14B499C, - 0x0BE34CC, 0x01C9C69, - 0x0ECA069, 0x01C2449, 0x0FDB166, 0x01C9C69, - 0x01C1C66, 0x0FC1C47, 0x01C1C66, - 0x10C5858, 0x1E4E3B8, 0x1A2F2F8, - ]; - foreach ($token as $x) { - $x = $x ^ N; + $token = [ + 0x14B499C, + 0x0BE34CC, 0x01C9C69, + 0x0ECA069, 0x01C2449, 0x0FDB166, 0x01C9C69, + 0x01C1C66, 0x0FC1C47, 0x01C1C66, + 0x10C5858, 0x1E4E3B8, 0x1A2F2F8, + ]; + foreach ($token as $x) { + $x = $x ^ N; - $x = sprintf('%025b', $x); - $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x); - $x = implode("\n", str_split($x, length: 5)); - echo "{$x}\n\n"; - }</programlisting> -<simpara>さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 -トークンを得るためには、ソースコードを読み、定数 <literal>N</literal> -を特定する必要がある。</simpara> -<simpara>ここでは、私の想定解を解説する。</simpara> -<section xml:id="_読解"> - <title>読解</title> - <simpara>まずはソースコードを読んでいく。</simpara> - <programlisting language="php" linenumbering="unnumbered">$token = [ - // 略 - ];</programlisting> -<simpara>数値からなる <literal>$token</literal> があり、各要素をループしている。</simpara> -<programlisting language="php" linenumbering="unnumbered"> $x = $x ^ N;</programlisting> -<simpara>まずは排他的論理和 (xor) を取り、</simpara> -<programlisting language="php" linenumbering="unnumbered"> $x = sprintf('%025b', $x);</programlisting> -<simpara>二進数に変換して、</simpara> -<programlisting language="php" linenumbering="unnumbered"> $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);</programlisting> -<simpara>0 を空白に、1 を <literal>#</literal> にし、</simpara> -<programlisting language="php" linenumbering="unnumbered"> $x = implode("\n", str_split($x, length: 5));</programlisting> -<simpara>5文字ごとに区切ったあと、改行で結合している。</simpara> -</section> -<section xml:id="_ヒント"> - <title>ヒント</title> - <simpara>次に、ソースコードに書いてあるヒントを読んでいく。</simpara> - <itemizedlist> - <listitem><literal>N</literal> それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている</listitem> - <listitem><literal>$token</literal> の各要素は、1文字を表す</listitem> - <listitem>1文字は 5x5 のセルからなる</listitem> - <listitem>出力されるのは、完全な PHPer トークンである</listitem> - </itemizedlist> -<simpara>ここで、PHPer トークンは必ず <literal>#</literal> 記号から始まることを思いだすと、 -<literal>$token</literal> の最初の数字 <literal>0x14B499C</literal> は、変換の結果 <literal>#</literal> -になるのではないかと予想される (なお、このことは、リポジトリの README -ファイルに追加ヒントとして書かれている)。</simpara> -</section> -<section xml:id="_解く"> - <title>解く</title> - <simpara>ここまでわかれば、あと一歩で解ける。すなわち、<literal>0x14B499C</literal> が <literal>#</literal> - に変換されるような <literal>N</literal> を見つければよい。</simpara> - <simpara><literal>N</literal> は高々</simpara> - <programlisting language="php" linenumbering="unnumbered">assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);</programlisting> - <simpara>なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。</simpara> - <programlisting language="php" linenumbering="unnumbered"><?php + $x = sprintf('%025b', $x); + $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x); + $x = implode("\n", str_split($x, length: 5)); + echo "{$x}\n\n"; + } + ]]> + </programlisting> + <simpara> + さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 + トークンを得るためには、ソースコードを読み、定数 <literal>N</literal> + を特定する必要がある。 + </simpara> + <simpara> + ここでは、私の想定解を解説する。 + </simpara> + <section xml:id="_読解"> + <title>読解</title> + <simpara> + まずはソースコードを読んでいく。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + $token = [ + // 略 + ]; + ]]> + </programlisting> + <simpara> + 数値からなる <literal>$token</literal> があり、各要素をループしている。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + $x = $x ^ N; + ]]> + </programlisting> + <simpara> + まずは排他的論理和 (xor) を取り、 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + $x = sprintf('%025b', $x); + ]]> + </programlisting> + <simpara> + 二進数に変換して、 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x); + ]]> + </programlisting> + <simpara> + 0 を空白に、1 を <literal>#</literal> にし、 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + $x = implode("\n", str_split($x, length: 5)); + ]]> + </programlisting> + <simpara> + 5文字ごとに区切ったあと、改行で結合している。 + </simpara> + </section> + <section xml:id="_ヒント"> + <title>ヒント</title> + <simpara> + 次に、ソースコードに書いてあるヒントを読んでいく。 + </simpara> + <itemizedlist> + <listitem><literal>N</literal> それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている</listitem> + <listitem><literal>$token</literal> の各要素は、1文字を表す</listitem> + <listitem>1文字は 5x5 のセルからなる</listitem> + <listitem>出力されるのは、完全な PHPer トークンである</listitem> + </itemizedlist> + <simpara> + ここで、PHPer トークンは必ず <literal>#</literal> 記号から始まることを思いだすと、 + <literal>$token</literal> の最初の数字 <literal>0x14B499C</literal> は、変換の結果 <literal>#</literal> + になるのではないかと予想される (なお、このことは、リポジトリの README + ファイルに追加ヒントとして書かれている)。 + </simpara> + </section> + <section xml:id="_解く"> + <title>解く</title> + <simpara> + ここまでわかれば、あと一歩で解ける。すなわち、<literal>0x14B499C</literal> が <literal>#</literal> + に変換されるような <literal>N</literal> を見つければよい。 + </simpara> + <simpara> + <literal>N</literal> は高々 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + assert(0 <= N && N <= 0b11111_11111_11111_11111_11111); + ]]> + </programlisting> + <simpara> + なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + <?php - $x = 0x14B499C; + $x = 0x14B499C; - $x = $x ^ N; + $x = $x ^ N; - $x = sprintf('%025b', $x); - $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x); - $x = implode("\n", str_split($x, length: 5)); + $x = sprintf('%025b', $x); + $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x); + $x = implode("\n", str_split($x, length: 5)); - assert($x === - " # # \n" . - "#####\n" . - " # # \n" . - "#####\n" . - " # # ");</programlisting> -<simpara>この一連の変換に対する逆変換を考えると、次のようになる。</simpara> -<programlisting language="php" linenumbering="unnumbered"><?php + assert($x === + " # # \n" . + "#####\n" . + " # # \n" . + "#####\n" . + " # # "); + ]]> + </programlisting> + <simpara> + この一連の変換に対する逆変換を考えると、次のようになる。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + <?php -$x = -" # # \n" . -"#####\n" . -" # # \n" . -"#####\n" . -" # # "; + $x = + " # # \n" . + "#####\n" . + " # # \n" . + "#####\n" . + " # # "; -$x = implode('', explode("\n", $x)); -$x = str_replace(search: [' ', '#'], replace: ['0', '1'], subject: $x); -$x = bindec($x); + $x = implode('', explode("\n", $x)); + $x = str_replace(search: [' ', '#'], replace: ['0', '1'], subject: $x); + $x = bindec($x); -$n = $x ^ 0x14B499C; + $n = $x ^ 0x14B499C; -echo "N = $n\n";</programlisting> -<simpara>これを実行すると、<literal>N</literal> が得られる。</simpara> -</section> -</section> -<section xml:id="_第3問_toquine_php"> - <title>第3問 toquine.php</title> - <simpara>ソースコードはこちら。</simpara> - <programlisting language="php" linenumbering="unnumbered"><?php + echo "N = $n\n"; + ]]> + </programlisting> + <simpara> + これを実行すると、<literal>N</literal> が得られる。 + </simpara> + </section> + </section> + <section xml:id="_第3問_toquine_php"> + <title>第3問 toquine.php</title> + <simpara> + ソースコードはこちら。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + <?php - // License: https://creativecommons.org/publicdomain/zero/1.0/ - // This is a quine-like program to generate a PHPer token. - // Execute it like this: php toquine.php | php | php | php | ... + // License: https://creativecommons.org/publicdomain/zero/1.0/ + // This is a quine-like program to generate a PHPer token. + // Execute it like this: php toquine.php | php | php | php | ... - $s = <<<'Q' - <?cuc - // Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/ - // Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra. - // Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ... - %f$f = %f; - $f = fge_ebg13($f); $kf = [ - %f, - ]; - $g = ahyy.snyfr; sbe ($v = 0; $v <= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr - $g .= vzcybqr("\a", fge_fcyvg(fge_ercynpr(['0','1'], [' ','##'], fcevags(pue(37) . '025o', $kf[$v])), 012)) . "\a\a"; - $jf = neenl_znc(sa($j) => vzcybqr(', ', $j), neenl_puhax(neenl_znc(sa($k) => fcevags('0k' . pue(37) . '07K', $k), $kf), 10)); - cevags($f, $g, fge_ebg13("<<<'Q'\a{$f}\aQ"), vzcybqr(",\a", $jf)); - Q; - $s = str_rot13($s); $xs = [ - 0x0AFABEA, 0x1F294A7, 0x1F2109F, 0x1F294A7, 0x0002800, 0x1F2109F, 0x0117041, 0x1F294A7, 0x1FAD6B5, 0x1F295B7, - 0x010FC21, 0x1FAD6B5, 0x1151151, 0x010FC21, 0x1F294A7, 0x1F295B7, 0x1FAD6B5, 0x1F294A7, 0x1F295B7, 0x1F8C63F, - 0x1F8C631, 0x1FAD6B5, 0x17AD6BD, 0x17AD6BD, 0x1F8C63F, 0x1F295B7, - ]; - $t = null.false; for ($i = 0; $i <= intdiv(__LINE__-035,6); ++$i) if (!isset($xs[$i])) break; else - $t .= implode("\n", str_split(str_replace(['0','1'], [' ','##'], sprintf(chr(37) . '025b', $xs[$i])), 012)) . "\n\n"; - $ws = array_map(fn($w) => implode(', ', $w), array_chunk(array_map(fn($x) => sprintf('0x' . chr(37) . '07X', $x), $xs), 10)); - printf($s, $t, str_rot13("<<<'D'\n{$s}\nD"), implode(",\n", $ws));</programlisting> -<simpara>コメントにもあるとおり、次のようにして実行すれば答えがでてくる。</simpara> -<programlisting language="shell-session" linenumbering="unnumbered">$ php toquine.php | php | php | php | ...</programlisting> -<simpara>実際にはもう少しパイプで繋げなければならない。</simpara> -<section xml:id="_解説_2"> - <title>解説</title> - <section xml:id="_プログラム全体_2"> - <title>プログラム全体</title> - <simpara>コメントにもあるとおり、これは quine (風) のプログラムになっている。 - Quine - とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。</simpara> - <simpara>このプログラムは、実行すると自身とほとんど同じプログラムを出力する。 - 異なるのはトークンになっている部分のみである。</simpara> -</section> -<section xml:id="_トークン"> - <title>トークン</title> - <simpara><literal>$xs</literal> がトークンに対応している。変換のロジックは <literal>riddle.php</literal> - とほぼ同じなので省略する。</simpara> -</section> -<section xml:id="_状態保持"> - <title>状態保持</title> - <simpara>トークンの何文字目まで出力したかを、ソースコードを変えずに (quine - なので) 覚えておく必要がある。 - このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<literal><emphasis>LINE</emphasis></literal> - から情報を取得している。</simpara> -</section> -<section xml:id="_rot_13"> - <title>ROT 13</title> - <simpara>Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。 - これがあまり美しくないので、<literal>toquine.php</literal> では、ROT 13 - 変換を使って難読化した。</simpara> -<simpara>それにしてもなぜこんなものが標準ライブラリに……。</simpara> -</section> -</section> -</section> -<section xml:id="_おわりに"> - <title>おわりに</title> - <simpara>解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。</simpara> - <simpara>今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、 - 来年は 5問、より面白い問題を持っていきます。</simpara> -<simpara>実はもう作りはじめているので、どうか来年もありますように……。</simpara> -</section> + $s = <<<'Q' + <?cuc + // Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/ + // Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra. + // Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ... + %f$f = %f; + $f = fge_ebg13($f); $kf = [ + %f, + ]; + $g = ahyy.snyfr; sbe ($v = 0; $v <= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr + $g .= vzcybqr("\a", fge_fcyvg(fge_ercynpr(['0','1'], [' ','##'], fcevags(pue(37) . '025o', $kf[$v])), 012)) . "\a\a"; + $jf = neenl_znc(sa($j) => vzcybqr(', ', $j), neenl_puhax(neenl_znc(sa($k) => fcevags('0k' . pue(37) . '07K', $k), $kf), 10)); + cevags($f, $g, fge_ebg13("<<<'Q'\a{$f}\aQ"), vzcybqr(",\a", $jf)); + Q; + $s = str_rot13($s); $xs = [ + 0x0AFABEA, 0x1F294A7, 0x1F2109F, 0x1F294A7, 0x0002800, 0x1F2109F, 0x0117041, 0x1F294A7, 0x1FAD6B5, 0x1F295B7, + 0x010FC21, 0x1FAD6B5, 0x1151151, 0x010FC21, 0x1F294A7, 0x1F295B7, 0x1FAD6B5, 0x1F294A7, 0x1F295B7, 0x1F8C63F, + 0x1F8C631, 0x1FAD6B5, 0x17AD6BD, 0x17AD6BD, 0x1F8C63F, 0x1F295B7, + ]; + $t = null.false; for ($i = 0; $i <= intdiv(__LINE__-035,6); ++$i) if (!isset($xs[$i])) break; else + $t .= implode("\n", str_split(str_replace(['0','1'], [' ','##'], sprintf(chr(37) . '025b', $xs[$i])), 012)) . "\n\n"; + $ws = array_map(fn($w) => implode(', ', $w), array_chunk(array_map(fn($x) => sprintf('0x' . chr(37) . '07X', $x), $xs), 10)); + printf($s, $t, str_rot13("<<<'D'\n{$s}\nD"), implode(",\n", $ws)); + ]]> + </programlisting> + <simpara> + コメントにもあるとおり、次のようにして実行すれば答えがでてくる。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ php toquine.php | php | php | php | ... + ]]> + </programlisting> + <simpara> + 実際にはもう少しパイプで繋げなければならない。 + </simpara> + <section xml:id="_解説_2"> + <title>解説</title> + <section xml:id="_プログラム全体_2"> + <title>プログラム全体</title> + <simpara> + コメントにもあるとおり、これは quine (風) のプログラムになっている。 + Quine + とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。 + </simpara> + <simpara> + このプログラムは、実行すると自身とほとんど同じプログラムを出力する。 + 異なるのはトークンになっている部分のみである。 + </simpara> + </section> + <section xml:id="_トークン"> + <title>トークン</title> + <simpara> + <literal>$xs</literal> がトークンに対応している。変換のロジックは <literal>riddle.php</literal> + とほぼ同じなので省略する。 + </simpara> + </section> + <section xml:id="_状態保持"> + <title>状態保持</title> + <simpara> + トークンの何文字目まで出力したかを、ソースコードを変えずに (quine + なので) 覚えておく必要がある。 + このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<literal><emphasis>LINE</emphasis></literal> + から情報を取得している。 + </simpara> + </section> + <section xml:id="_rot_13"> + <title>ROT 13</title> + <simpara> + Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。 + これがあまり美しくないので、<literal>toquine.php</literal> では、ROT 13 + 変換を使って難読化した。 + </simpara> + <simpara> + それにしてもなぜこんなものが標準ライブラリに……。 + </simpara> + </section> + </section> + </section> + <section xml:id="outro"> + <title>おわりに</title> + <simpara> + 解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。 + </simpara> + <simpara> + 今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、 + 来年は 5問、より面白い問題を持っていきます。 + </simpara> + <simpara> + 実はもう作りはじめているので、どうか来年もありますように……。 + </simpara> + </section> </article> diff --git a/content/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal.xml b/content/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal.xml index 0acaad5..f80a730 100644 --- a/content/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal.xml +++ b/content/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal.xml @@ -16,68 +16,110 @@ </revision> </revhistory> </info> - <section xml:id="_はじめに"> + <section xml:id="intro"> <title>はじめに</title> - <simpara>こんなものを作った。</simpara> - <literallayout class="monospaced">$ term-banner 'Hello, World!' 'こんにちは、' '世界!'</literallayout> - <simpara>image::https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png[term-banner - のスクリーンショット]</simpara> - <simpara>コマンドライン引数として渡した文字列をターミナルに大きく表示する。</simpara> - <simpara>リポジトリはこちら: <link xl:href="https://github.com/nsfisis/term-banner">https://github.com/nsfisis/term-banner</link></simpara> -</section> -<section xml:id="_motivation"> - <title>Motivation</title> - <simpara>以前、https://github.com/nsfisis/big-clock-mode[big-clock-mode] - という似たようなプログラムを書いた。 これは tmux の <literal>:clock-mode</literal> - コマンドに着想を得たもので、<literal>:clock-mode</literal> - よりも大きく現在時刻を表示する。</simpara> -<simpara><literal>big-clock-mode</literal> - を開発したのは、次のようなシチュエーションで使うためである。 - 弊社では現在リモートワークが基本だが、web - 会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。 - こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。</simpara> -<simpara>それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。</simpara> -<simpara>しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。 -どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。</simpara> -<simpara>そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。 -まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。</simpara> -</section> -<section xml:id="_プログラム"> - <title>プログラム</title> - <simpara>全体の流れは次のようになっている。</simpara> - <orderedlist numeration="arabic"> - <listitem>フォントファイルを読み込む</listitem> - <listitem>コマンドライン引数を Shift-JIS に変換する (フォントが Shift-JIS 基準で並んでいるため)</listitem> - <listitem>1文字ずつレンダリングしていく</listitem> - </orderedlist> -<simpara><literal>big-clock-mode</literal> が Go 製なので、今回も Go で書いた。 PNG -が標準ライブラリにあったり、Shift-JIS -のエンコーディングが準標準ライブラリにあったりしたのは助かった。</simpara> -<simpara>フォントファイルは <literal>go:embed</literal> - で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。 - 仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。</simpara> -</section> -<section xml:id="_フォント"> - <title>フォント</title> - <simpara>フリーの 8x8 - ビットマップフォントである、https://littlelimit.net/misaki.htm[美咲フォント - 2021-05-05a 版] を使わせていただいた。</simpara> -<simpara>はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。 -同じく 8x8 -で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。</simpara> -<simpara>美咲フォントは、平仮名・片仮名に留まらず、JIS -第一・第二水準の漢字までサポートしている。 -第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。</simpara> -<simpara>さらに言うと、実のところ美咲フォントは実サイズ 7x7 -で作られており、余白が設けられている。 -これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。 -おかげでコーディングまで楽になった。</simpara> -<simpara>ゴシック体と明朝体があったが、私の好みで明朝体の方にした。 -ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。</simpara> -<simpara>2022-04-27 追記: <literal>-f</literal> オプションで選べるようにした。</simpara> -</section> -<section xml:id="_おわりに"> - <title>おわりに</title> - <simpara>あなたもターミナルに住んでみませんか?</simpara> -</section> + <simpara> + こんなものを作った。 + </simpara> + <literallayout class="monospaced"> + <![CDATA[ + $ term-banner 'Hello, World!' 'こんにちは、' '世界!' + ]]> + </literallayout> + <simpara> + image::https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png[term-banner + のスクリーンショット] + </simpara> + <simpara> + コマンドライン引数として渡した文字列をターミナルに大きく表示する。 + </simpara> + <simpara> + リポジトリはこちら: <link xl:href="https://github.com/nsfisis/term-banner">https://github.com/nsfisis/term-banner</link> + </simpara> + </section> + <section xml:id="_motivation"> + <title>Motivation</title> + <simpara> + 以前、https://github.com/nsfisis/big-clock-mode[big-clock-mode] + という似たようなプログラムを書いた。 これは tmux の <literal>:clock-mode</literal> + コマンドに着想を得たもので、<literal>:clock-mode</literal> + よりも大きく現在時刻を表示する。 + </simpara> + <simpara> + <literal>big-clock-mode</literal> + を開発したのは、次のようなシチュエーションで使うためである。 + 弊社では現在リモートワークが基本だが、web + 会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。 + こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。 + </simpara> + <simpara> + それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。 + </simpara> + <simpara> + しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。 + どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。 + </simpara> + <simpara> + そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。 + まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。 + </simpara> + </section> + <section xml:id="_プログラム"> + <title>プログラム</title> + <simpara> + 全体の流れは次のようになっている。 + </simpara> + <orderedlist numeration="arabic"> + <listitem>フォントファイルを読み込む</listitem> + <listitem>コマンドライン引数を Shift-JIS に変換する (フォントが Shift-JIS 基準で並んでいるため)</listitem> + <listitem>1文字ずつレンダリングしていく</listitem> + </orderedlist> + <simpara> + <literal>big-clock-mode</literal> が Go 製なので、今回も Go で書いた。 PNG + が標準ライブラリにあったり、Shift-JIS + のエンコーディングが準標準ライブラリにあったりしたのは助かった。 + </simpara> + <simpara> + フォントファイルは <literal>go:embed</literal> + で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。 + 仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。 + </simpara> + </section> + <section xml:id="_フォント"> + <title>フォント</title> + <simpara> + フリーの 8x8 + ビットマップフォントである、https://littlelimit.net/misaki.htm[美咲フォント + 2021-05-05a 版] を使わせていただいた。 + </simpara> + <simpara> + はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。 + 同じく 8x8 + で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。 + </simpara> + <simpara> + 美咲フォントは、平仮名・片仮名に留まらず、JIS + 第一・第二水準の漢字までサポートしている。 + 第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。 + </simpara> + <simpara> + さらに言うと、実のところ美咲フォントは実サイズ 7x7 + で作られており、余白が設けられている。 + これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。 + おかげでコーディングまで楽になった。 + </simpara> + <simpara> + ゴシック体と明朝体があったが、私の好みで明朝体の方にした。 + ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。 + </simpara> + <simpara> + 2022-04-27 追記: <literal>-f</literal> オプションで選べるようにした。 + </simpara> + </section> + <section xml:id="outro"> + <title>おわりに</title> + <simpara> + あなたもターミナルに住んでみませんか? + </simpara> + </section> </article> diff --git a/content/posts/2022-05-01/phperkaigi-2022.xml b/content/posts/2022-05-01/phperkaigi-2022.xml index 106b1db..1290abd 100644 --- a/content/posts/2022-05-01/phperkaigi-2022.xml +++ b/content/posts/2022-05-01/phperkaigi-2022.xml @@ -17,109 +17,167 @@ </revision> </revhistory> </info> - <section xml:id="_はじめに"> + <section xml:id="intro"> <title>はじめに</title> - <simpara>2022-04-09 から 2022-04-11 - にかけて開催された、https://phperkaigi.jp/2022/[PHPerKaigi 2022] - に、一般参加者として参加した。 - 弊社https://www.dgcircus.com/[デジタルサーカス株式会社] - はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</simpara> - <simpara>昨年のレポートは<link xl:href="/posts/2021-03-30/phperkaigi-2021">こちら</link>。</simpara> -</section> -<section xml:id="_感想"> - <title>感想</title> - <section xml:id="_厳選おすすめトーク"> - <title>厳選おすすめトーク</title> - <simpara>多くの素晴らしいトークの中から、特におすすめのものを - 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。</simpara> - <simpara><link xl:href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし - - 堅牢なコードを導く様々な設計のヒント</link></simpara> -<blockquote> - <simpara>PHP - はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。</simpara> -<simpara>本講演では PHP 8.1 -をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。</simpara> -</blockquote> -<simpara><link xl:href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</link></simpara> -<blockquote> - <simpara>PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice - 理解していますか?<br/> - これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!<br/> - またそれらを理解した上でのエラーハンドリングを学びましょう。</simpara> -</blockquote> -<simpara><link xl:href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</link></simpara> -<blockquote> - <simpara>毎日流れてくるエラーに皆さんはどう向き合ってますか?<br/> - エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。<br/> - サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、<br/> - エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。</simpara> -</blockquote> -<simpara><link xl:href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</link></simpara> -<blockquote> - <simpara>昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。</simpara> - <simpara>最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には<br/> - ・「(私の思う)良い設計」を実現するための意思決定<br/> - ・「ISUCONの問題」という位置付けに由来する取捨選択<br/> - ・移植中に遭遇したトラブルとその解決策<br/> - といった文脈や葛藤が存在しています。</simpara> - <simpara>本発表はそれらを共有することで<br/> - ・PHPアプリケーションの設計、実装事例として役立ててもらう<br/> - ・ISUCONの言語移植に興味を持ってもらう<br/> - ・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう<br/> - ことを目的とします。</simpara> -</blockquote> -<simpara><link xl:href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</link></simpara> -<blockquote> - <simpara>サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。</simpara> - <simpara>フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。</simpara> - <simpara>このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。</simpara> -</blockquote> -</section> -<section xml:id="_トークン問題の作成"> - <title>トークン問題の作成</title> - <simpara>今回は、PHPer チャレンジ用に弊社のトークン問題を - 3題作成した。こちらについては<link xl:href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</link>ので、そちらを参照されたい。</simpara> -</section> -<section xml:id="_phper_チャレンジ"> - <title>PHPer チャレンジ</title> - <simpara><link xl:href="https://fortee.jp/phperkaigi-2022/challenge">1位</link>になった。<br/> - また、賞品として <link xl:href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</link> - をいただいた。</simpara> -</section> -<section xml:id="_カンファレンス全体への感想"> - <title>カンファレンス全体への感想</title> - <simpara><link xl:href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</link> - では、こんなことを書いた。</simpara> - <blockquote> - <simpara>1つ個人的な反省点としては、(中略) Discord - しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。<br/> - まあ初カンファレンスだし、とお茶を濁しておこう。</simpara> -</blockquote> -<simpara>この反省を踏まえ、今年は積極的にほかの場 (公式の Discord -サーバや、アンカンファレンス) にも参加した。<br/> -これにより、参加体験の質がはるかに向上した。特に Discord -に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる -(ことが多い) -ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。</simpara> -<simpara>なお、アンカンファレンスについては、1日目の終わりにhttps://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e[トークン問題の解説放送]もおこなった。</simpara> -<simpara>また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。 -今年は -3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。</simpara> -</section> + <simpara> + 2022-04-09 から 2022-04-11 + にかけて開催された、https://phperkaigi.jp/2022/[PHPerKaigi 2022] + に、一般参加者として参加した。 + 弊社https://www.dgcircus.com/[デジタルサーカス株式会社] + はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。 + </simpara> + <simpara> + 昨年のレポートは<link xl:href="/posts/2021-03-30/phperkaigi-2021">こちら</link>。 + </simpara> + </section> + <section xml:id="_感想"> + <title>感想</title> + <section xml:id="_厳選おすすめトーク"> + <title>厳選おすすめトーク</title> + <simpara> + 多くの素晴らしいトークの中から、特におすすめのものを + 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。 + </simpara> + <simpara> + <link xl:href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし + - 堅牢なコードを導く様々な設計のヒント</link> + </simpara> + <blockquote> + <simpara> + PHP + はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。 + </simpara> + <simpara> + 本講演では PHP 8.1 + をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。 + </simpara> + </blockquote> + <simpara> + <link xl:href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</link> + </simpara> + <blockquote> + <simpara> + PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice + 理解していますか?<br/> + これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!<br/> + またそれらを理解した上でのエラーハンドリングを学びましょう。 + </simpara> + </blockquote> + <simpara> + <link xl:href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</link> + </simpara> + <blockquote> + <simpara> + 毎日流れてくるエラーに皆さんはどう向き合ってますか?<br/> + エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。<br/> + サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、<br/> + エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。 + </simpara> + </blockquote> + <simpara> + <link xl:href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</link> + </simpara> + <blockquote> + <simpara> + 昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。 + </simpara> + <simpara> + 最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には<br/> + ・「(私の思う)良い設計」を実現するための意思決定<br/> + ・「ISUCONの問題」という位置付けに由来する取捨選択<br/> + ・移植中に遭遇したトラブルとその解決策<br/> + といった文脈や葛藤が存在しています。 + </simpara> + <simpara> + 本発表はそれらを共有することで<br/> + ・PHPアプリケーションの設計、実装事例として役立ててもらう<br/> + ・ISUCONの言語移植に興味を持ってもらう<br/> + ・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう<br/> + ことを目的とします。 + </simpara> + </blockquote> + <simpara> + <link xl:href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</link> + </simpara> + <blockquote> + <simpara> + サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。 + </simpara> + <simpara> + フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。 + </simpara> + <simpara> + このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。 + </simpara> + </blockquote> + </section> + <section xml:id="_トークン問題の作成"> + <title>トークン問題の作成</title> + <simpara> + 今回は、PHPer チャレンジ用に弊社のトークン問題を + 3題作成した。こちらについては<link xl:href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</link>ので、そちらを参照されたい。 + </simpara> + </section> + <section xml:id="_phper_チャレンジ"> + <title>PHPer チャレンジ</title> + <simpara> + <link xl:href="https://fortee.jp/phperkaigi-2022/challenge">1位</link>になった。<br/> + また、賞品として <link xl:href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</link> + をいただいた。 + </simpara> + </section> + <section xml:id="_カンファレンス全体への感想"> + <title>カンファレンス全体への感想</title> + <simpara> + <link xl:href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</link> + では、こんなことを書いた。 + </simpara> + <blockquote> + <simpara> + 1つ個人的な反省点としては、(中略) Discord + しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。<br/> + まあ初カンファレンスだし、とお茶を濁しておこう。 + </simpara> + </blockquote> + <simpara> + この反省を踏まえ、今年は積極的にほかの場 (公式の Discord + サーバや、アンカンファレンス) にも参加した。<br/> + これにより、参加体験の質がはるかに向上した。特に Discord + に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる + (ことが多い) + ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。 + </simpara> + <simpara> + なお、アンカンファレンスについては、1日目の終わりにhttps://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e[トークン問題の解説放送]もおこなった。 + </simpara> + <simpara> + また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。 + 今年は + 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。 + </simpara> + </section> </section> <section xml:id="_そして来年へ"> <title>そして来年へ……?</title> - <simpara>PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の - 4つを目標としたい。</simpara> -<itemizedlist> - <listitem>プロポーザルを出す</listitem> - <listitem>PHPer チャレンジのトークン問題を 5題作成する</listitem> - <listitem>現地に行く</listitem> - <listitem>PHPer チャレンジで圧勝する</listitem> -</itemizedlist> -<simpara><hr/></simpara> -<simpara>最後になりましたが、PHPerKaigi -のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。</simpara> -<simpara>ではまた来年。</simpara> + <simpara> + PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の + 4つを目標としたい。 + </simpara> + <itemizedlist> + <listitem>プロポーザルを出す</listitem> + <listitem>PHPer チャレンジのトークン問題を 5題作成する</listitem> + <listitem>現地に行く</listitem> + <listitem>PHPer チャレンジで圧勝する</listitem> + </itemizedlist> + <simpara> + <hr/> + </simpara> + <simpara> + 最後になりましたが、PHPerKaigi + のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。 + </simpara> + <simpara> + ではまた来年。 + </simpara> </section> </article> diff --git a/content/posts/2022-08-27/php-conference-okinawa-code-golf.xml b/content/posts/2022-08-27/php-conference-okinawa-code-golf.xml index 660b4ad..76fc041 100644 --- a/content/posts/2022-08-27/php-conference-okinawa-code-golf.xml +++ b/content/posts/2022-08-27/php-conference-okinawa-code-golf.xml @@ -17,78 +17,114 @@ </revision> </revhistory> </info> - <section xml:id="_はじめに"> + <section xml:id="intro"> <title>はじめに</title> - <simpara>本日 <link xl:href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</link> - が開催された (らしい)。</simpara> - <simpara>カンファレンスには参加できなかったものの、懇親会の LT - で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。</simpara> - <simpara>ツイート: <link xl:href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</link><br/> - スライド: - <link xl:href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</link></simpara> -</section> -<section xml:id="_解"> - <title>解</title> - <simpara>細かいレギュレーションは不明だったので、勝手に定めた。</simpara> - <itemizedlist> - <listitem>コマンドライン引数の第1引数で受けとる</listitem> - <listitem>結果は標準出力に出す</listitem> - <listitem>コンマの直後にはスペースを1つ置く</listitem> - <listitem>末尾コンマは禁止</listitem> - <listitem>数字でないものは入ってこないものとする</listitem> - <listitem>負数は入ってこないものとする</listitem> - </itemizedlist> - <simpara>書いたものがこちら:</simpara> - <programlisting language="php" linenumbering="unnumbered">[<?php $n=$argv[1];foreach([1e4,5e3,2e3,1e3,500,100,50,10,5,1]as$x)for(;$n>=$x;$n-=$x)$r[]=$x;echo implode(', ',$r??[]);?>]</programlisting> - <simpara>しめて 123 バイトとなった (末尾改行を含めずにカウント)。</simpara> - <simpara>こちらは改行とスペースを追加したバージョン:</simpara> - <programlisting language="php" linenumbering="unnumbered">[<?php + <simpara> + 本日 <link xl:href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</link> + が開催された (らしい)。 + </simpara> + <simpara> + カンファレンスには参加できなかったものの、懇親会の LT + で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。 + </simpara> + <simpara> + ツイート: <link xl:href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</link><br/> + スライド: + <link xl:href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</link> + </simpara> + </section> + <section xml:id="_解"> + <title>解</title> + <simpara> + 細かいレギュレーションは不明だったので、勝手に定めた。 + </simpara> + <itemizedlist> + <listitem>コマンドライン引数の第1引数で受けとる</listitem> + <listitem>結果は標準出力に出す</listitem> + <listitem>コンマの直後にはスペースを1つ置く</listitem> + <listitem>末尾コンマは禁止</listitem> + <listitem>数字でないものは入ってこないものとする</listitem> + <listitem>負数は入ってこないものとする</listitem> + </itemizedlist> + <simpara> + 書いたものがこちら: + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + [<?php $n=$argv[1];foreach([1e4,5e3,2e3,1e3,500,100,50,10,5,1]as$x)for(;$n>=$x;$n-=$x)$r[]=$x;echo implode(', ',$r??[]);?>] + ]]> + </programlisting> + <simpara> + しめて 123 バイトとなった (末尾改行を含めずにカウント)。 + </simpara> + <simpara> + こちらは改行とスペースを追加したバージョン: + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + [<?php - $n = $argv[1]; - foreach ([1e4, 5e3, 2e3, 1e3, 500, 100, 50, 10, 5, 1] as $x) - for (; $n >= $x; $n -= $x) - $r[] = $x; - echo implode(', ', $r ?? []); + $n = $argv[1]; + foreach ([1e4, 5e3, 2e3, 1e3, 500, 100, 50, 10, 5, 1] as $x) + for (; $n >= $x; $n -= $x) + $r[] = $x; + echo implode(', ', $r ?? []); - ?>]</programlisting> -</section> -<section xml:id="_使用したテクニック"> - <title>使用したテクニック</title> - <section xml:id="_指数表記"> - <title>指数表記</title> - <simpara>割と多くの言語のゴルフで使えるテクニック。<literal>e</literal> - を用いた指数表記で、大きな数を短く表す。このコードでは - <literal>10000</literal>、<literal>5000</literal>、<literal>2000</literal>、<literal>1000</literal> を指数表記している。</simpara> + ?>] + ]]> + </programlisting> + </section> + <section xml:id="_使用したテクニック"> + <title>使用したテクニック</title> + <section xml:id="_指数表記"> + <title>指数表記</title> + <simpara> + 割と多くの言語のゴルフで使えるテクニック。<literal>e</literal> + を用いた指数表記で、大きな数を短く表す。このコードでは + <literal>10000</literal>、<literal>5000</literal>、<literal>2000</literal>、<literal>1000</literal> を指数表記している。 + </simpara> + </section> + <section xml:id="_foreach_や_for_の中身を1つの文に"> + <title>foreach や for の中身を1つの文に</title> + <simpara> + <literal>foreach</literal>、<literal>for</literal>、<literal>if</literal> などの後ろには、通常 <literal>{</literal> + を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<literal>{</literal> と <literal>}</literal> + を省略できる。C言語などでも使える。 + </simpara> + </section> + <section xml:id="_r_に初期値を入れない"> + <title>$r に初期値を入れない</title> + <simpara> + PHP では、<literal>$r[] = …​</literal> + のような配列の末尾に追加する式を実行したとき、<literal>$r</literal> が未定義だった場合は + <literal>$r</literal> + を勝手に定義して空の配列で初期化してくれる。これを利用すると、<literal>$r = [];</literal> + のような初期化が不要になる。 + </simpara> + <simpara> + ただし、プログラムに 0 が渡されるとループを一度も回らないので、<literal>$r</literal> + が未定義になってしまい、<literal>implode()</literal> + に渡すところでエラーになる。それを防ぐために <literal>$r ?? []</literal> を使っている。 + </simpara> + <simpara> + もし 0 が渡されたケースを無視するなら、これが不要になるので 4 + バイト縮む。 + </simpara> + </section> + <section xml:id="_php_タグの外に文字列を置く"> + <title>PHP タグの外に文字列を置く</title> + <simpara> + PHP では、<literal><?php</literal> <literal>?></literal> + で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず + <literal>[</literal> と <literal>]</literal> を出力するので、そのまま書いてやればよい。 + </simpara> + </section> </section> - <section xml:id="_foreach_や_for_の中身を1つの文に"> - <title>foreach や for の中身を1つの文に</title> - <simpara><literal>foreach</literal>、<literal>for</literal>、<literal>if</literal> などの後ろには、通常 <literal>{</literal> - を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<literal>{</literal> と <literal>}</literal> - を省略できる。C言語などでも使える。</simpara> + <section xml:id="outro"> + <title>おわりに</title> + <simpara> + 最後になりましたが、https://twitter.com/m3m0r7[めもりー] + さん、楽しい問題をありがとうございました。 + </simpara> </section> - <section xml:id="_r_に初期値を入れない"> - <title>$r に初期値を入れない</title> - <simpara>PHP では、<literal>$r[] = …​</literal> - のような配列の末尾に追加する式を実行したとき、<literal>$r</literal> が未定義だった場合は - <literal>$r</literal> - を勝手に定義して空の配列で初期化してくれる。これを利用すると、<literal>$r = [];</literal> - のような初期化が不要になる。</simpara> - <simpara>ただし、プログラムに 0 が渡されるとループを一度も回らないので、<literal>$r</literal> - が未定義になってしまい、<literal>implode()</literal> - に渡すところでエラーになる。それを防ぐために <literal>$r ?? []</literal> を使っている。</simpara> - <simpara>もし 0 が渡されたケースを無視するなら、これが不要になるので 4 - バイト縮む。</simpara> -</section> -<section xml:id="_php_タグの外に文字列を置く"> - <title>PHP タグの外に文字列を置く</title> - <simpara>PHP では、<literal><?php</literal> <literal>?></literal> - で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず - <literal>[</literal> と <literal>]</literal> を出力するので、そのまま書いてやればよい。</simpara> -</section> -</section> -<section xml:id="_おわりに"> - <title>おわりに</title> - <simpara>最後になりましたが、https://twitter.com/m3m0r7[めもりー] - さん、楽しい問題をありがとうございました。</simpara> -</section> </article> diff --git a/content/posts/2022-08-31/support-for-communty-is-employee-benefits.xml b/content/posts/2022-08-31/support-for-communty-is-employee-benefits.xml index 36db0a6..a28b96d 100644 --- a/content/posts/2022-08-31/support-for-communty-is-employee-benefits.xml +++ b/content/posts/2022-08-31/support-for-communty-is-employee-benefits.xml @@ -12,37 +12,61 @@ </revision> </revhistory> </info> - <section xml:id="_はじめに"> + <section xml:id="intro"> <title>はじめに</title> - <simpara><emphasis role="strong">注: - これは私個人の意見であり、所属する組織を代表するものではありません。</emphasis></simpara> -<simpara>先日、私の勤める <link xl:href="https://www.dgcircus.com/">デジタルサーカス株式会社</link> が -<link xl:href="https://opencollective.com/phpfoundation">PHP Foundation</link> へ $2,000 -の寄付をおこないました。</simpara> -<simpara>記事: <link xl:href="https://www.dgcircus.com/news/581">https://www.dgcircus.com/news/581</link></simpara> -<simpara>本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。</simpara> + <simpara> + <emphasis role="strong">注: + これは私個人の意見であり、所属する組織を代表するものではありません。</emphasis> + </simpara> + <simpara> + 先日、私の勤める <link xl:href="https://www.dgcircus.com/">デジタルサーカス株式会社</link> が + <link xl:href="https://opencollective.com/phpfoundation">PHP Foundation</link> へ $2,000 + の寄付をおこないました。 + </simpara> + <simpara> + 記事: <link xl:href="https://www.dgcircus.com/news/581">https://www.dgcircus.com/news/581</link> + </simpara> + <simpara> + 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。 + </simpara> </section> <section xml:id="_なぜ"> <title>なぜ?</title> - <simpara>組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。</simpara> - <simpara>当時の考えを端的にまとめた社内チャットの投稿があったので、それを引用します:</simpara> + <simpara> + 組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。 + </simpara> + <simpara> + 当時の考えを端的にまとめた社内チャットの投稿があったので、それを引用します: + </simpara> <blockquote> - <simpara>結局これを通したい (私の中での) - 最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、寄付の報告が流れてきたり、OSS - のフリーライドの話が流れてきたりするたびに、自尊心が毀損される、というか - (これは大袈裟すぎる表現で、実際にはそこまで明確に傷ついているわけではありませんが)。</simpara> - <simpara>追記: 「肩身が狭くなる」というのがより適切でした。</simpara> -</blockquote> -<simpara>※文中の「↑にしても」は、ここに載せていない別の投稿を指しています。</simpara> -<simpara>OSS を金銭的に支援したり、技術カンファレンスへ協賛したり (あるいは -<link xl:href="https://twitter.com/tomzoh">CTO</link> がカンファレンスを年2で主催したり: -<link xl:href="https://iosdc.jp">iOSDC</link> <link xl:href="https://phperkaigi.jp">PHPerKaigi</link>) -といった行為は、コミュニティへの貢献であると同時に、社員に対する精神的福利厚生でもあると言えるでしょう -(知らんけど)。これらは、技術や技術者を大切にする組織である、ということの、対外的にも対内的にも強力なメッセージなのです。</simpara> -<simpara>以上が、私が社内で寄付の件を進めた (かなり私的な) 理由です。</simpara> + <simpara> + 結局これを通したい (私の中での) + 最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、寄付の報告が流れてきたり、OSS + のフリーライドの話が流れてきたりするたびに、自尊心が毀損される、というか + (これは大袈裟すぎる表現で、実際にはそこまで明確に傷ついているわけではありませんが)。 + </simpara> + <simpara> + 追記: 「肩身が狭くなる」というのがより適切でした。 + </simpara> + </blockquote> + <simpara> + ※文中の「↑にしても」は、ここに載せていない別の投稿を指しています。 + </simpara> + <simpara> + OSS を金銭的に支援したり、技術カンファレンスへ協賛したり (あるいは + <link xl:href="https://twitter.com/tomzoh">CTO</link> がカンファレンスを年2で主催したり: + <link xl:href="https://iosdc.jp">iOSDC</link> <link xl:href="https://phperkaigi.jp">PHPerKaigi</link>) + といった行為は、コミュニティへの貢献であると同時に、社員に対する精神的福利厚生でもあると言えるでしょう + (知らんけど)。これらは、技術や技術者を大切にする組織である、ということの、対外的にも対内的にも強力なメッセージなのです。 + </simpara> + <simpara> + 以上が、私が社内で寄付の件を進めた (かなり私的な) 理由です。 + </simpara> </section> -<section xml:id="_おわりに"> +<section xml:id="outro"> <title>おわりに</title> - <simpara>最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。この場を借りて感謝申し上げます。</simpara> + <simpara> + 最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。この場を借りて感謝申し上げます。 + </simpara> </section> </article> diff --git a/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.xml b/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.xml index 32c88e8..d39526a 100644 --- a/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.xml +++ b/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.xml @@ -21,47 +21,57 @@ </info> <section xml:id="_記事の構成について"> <title>記事の構成について</title> - <simpara>この記事は、普通の fizzbuzz - を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、 - <link xl:href="https://gist.github.com/nsfisis/04c227d5a419867472a0b23a83ad2919#file-fizzbuzz-php-2-letters-per-line-and-supports-php-8-x-without-warnings">このページ</link> - にソースコードがあるので、そちらを先に見てほしい。</simpara> -</section> -<section xml:id="_レギュレーション"> - <title>レギュレーション</title> - <simpara>PHP で、次のような制約の下に fizzbuzz を書いた。</simpara> - <itemizedlist> - <listitem> - 1行あたりの文字数は2文字までに収めること (ただし <literal><?php</literal> タグは除く) - <itemizedlist> - <listitem> - 厳密な定義: <literal><?php</literal> タグ以降のソースコードが、2 byte ごとに - ラインフィード (LF) で区切られること - </listitem> - </itemizedlist> - </listitem> - <listitem>スペースやタブを使用しないこと</listitem> - <listitem> - ループのアンロールをしないこと + <simpara> + この記事は、普通の fizzbuzz + を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、 + <link xl:href="https://gist.github.com/nsfisis/04c227d5a419867472a0b23a83ad2919#file-fizzbuzz-php-2-letters-per-line-and-supports-php-8-x-without-warnings">このページ</link> + にソースコードがあるので、そちらを先に見てほしい。 + </simpara> + </section> + <section xml:id="_レギュレーション"> + <title>レギュレーション</title> + <simpara> + PHP で、次のような制約の下に fizzbuzz を書いた。 + </simpara> <itemizedlist> - <listitem>100 回ループの代わりに 100 回コードをコピペ、というのは禁止</listitem> + <listitem> + 1行あたりの文字数は2文字までに収めること (ただし <literal><?php</literal> タグは除く) + <itemizedlist> + <listitem> + 厳密な定義: <literal><?php</literal> タグ以降のソースコードが、2 byte ごとに + ラインフィード (LF) で区切られること + </listitem> + </itemizedlist> + </listitem> + <listitem>スペースやタブを使用しないこと</listitem> + <listitem> + ループのアンロールをしないこと + <itemizedlist> + <listitem>100 回ループの代わりに 100 回コードをコピペ、というのは禁止</listitem> + </itemizedlist> + </listitem> + <listitem>PHP 7.4〜8.1 で動作すること</listitem> + <listitem>実行時に Notice や Warning が出ないこと</listitem> + <listitem>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)</listitem> </itemizedlist> - </listitem> - <listitem>PHP 7.4〜8.1 で動作すること</listitem> - <listitem>実行時に Notice や Warning が出ないこと</listitem> - <listitem>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)</listitem> -</itemizedlist> -<simpara>備考: PHP には <literal>short_open_tag</literal> - というオプションがあり、これを有効にするとファイル冒頭の <literal><?php</literal> - の代わりに <literal><?</literal> - を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト - off になっている環境が多いようなので、今回は使わないことにした。</simpara> -</section> -<section xml:id="_主な障害"> - <title>主な障害</title> - <simpara>1行あたりの文字数など、適当に改行を挟めばいいだけではないのか?</simpara> - <simpara>特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。</simpara> - <programlisting language="c" linenumbering="unnumbered"> - <![CDATA[ + <simpara> + 備考: PHP には <literal>short_open_tag</literal> + というオプションがあり、これを有効にするとファイル冒頭の <literal><?php</literal> + の代わりに <literal><?</literal> + を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト + off になっている環境が多いようなので、今回は使わないことにした。 + </simpara> + </section> + <section xml:id="_主な障害"> + <title>主な障害</title> + <simpara> + 1行あたりの文字数など、適当に改行を挟めばいいだけではないのか? + </simpara> + <simpara> + 特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。 + </simpara> + <programlisting language="c" linenumbering="unnumbered"> + <![CDATA[ #\ i\ n\ @@ -70,7 +80,7 @@ u\ d\ e\ - <\ + <\ s\ t\ d\ @@ -78,7 +88,7 @@ o\ .\ h\ - >\ + >\ /* */ i\ @@ -101,7 +111,7 @@ */ i= 1; - i< + i< 1\ 0\ 0; @@ -136,99 +146,127 @@ ); /* あとは同じように普通のプログラムを変形するだけなので省略 */ - ]]> - </programlisting> -<simpara>バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。</simpara> -<simpara>さて、PHP -ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、<literal>echo</literal> -で出力することや、<literal>for</literal> でループすること、<literal>new</literal> -でインスタンスを生成することができない。特に、出力は fizzbuzz -をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。</simpara> -<simpara>当然、名前が3文字以上ある関数も使えない。なお、標準 PHP -の範囲内において、名前が 2文字以下の関数は以下のとおりである:</simpara> -<itemizedlist> - <listitem> - <literal>_</literal>: <literal>gettext</literal> のエイリアス - </listitem> - <listitem> - <literal>dl</literal>: 拡張モジュールをロードする - </listitem> - <listitem> - <literal>pi</literal>: 円周率を返す - </listitem> -</itemizedlist> -<simpara>(環境によって多少は変わるかも)</simpara> -<simpara>2文字の関数を定義しまくった拡張モジュールを用意しておいて <literal>dl()</literal> - で読み込む行為は、レギュレーションで定めた</simpara> -<blockquote> - <itemizedlist> - <listitem>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと) - </listitem> -</itemizedlist> -</blockquote> -<simpara>に反する -(というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。</simpara> -<simpara>また、2文字だと文字列がまともに書けないのも辛い。<literal>''</literal> だけで -2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP -では文字列リテラル中に生の改行が書けるので</simpara> -<programlisting language="php" linenumbering="unnumbered"> - <![CDATA[ + ]]> + </programlisting> + <simpara> + バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。 + </simpara> + <simpara> + さて、PHP + ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、<literal>echo</literal> + で出力することや、<literal>for</literal> でループすること、<literal>new</literal> + でインスタンスを生成することができない。特に、出力は fizzbuzz + をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。 + </simpara> + <simpara> + 当然、名前が3文字以上ある関数も使えない。なお、標準 PHP + の範囲内において、名前が 2文字以下の関数は以下のとおりである: + </simpara> + <itemizedlist> + <listitem> + <literal>_</literal>: <literal>gettext</literal> のエイリアス + </listitem> + <listitem> + <literal>dl</literal>: 拡張モジュールをロードする + </listitem> + <listitem> + <literal>pi</literal>: 円周率を返す + </listitem> + </itemizedlist> + <simpara> + (環境によって多少は変わるかも) + </simpara> + <simpara> + 2文字の関数を定義しまくった拡張モジュールを用意しておいて <literal>dl()</literal> + で読み込む行為は、レギュレーションで定めた + </simpara> + <blockquote> + <itemizedlist> + <listitem>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと) + </listitem> + </itemizedlist> + </blockquote> + <simpara> + に反する + (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。 + </simpara> + <simpara> + また、2文字だと文字列がまともに書けないのも辛い。<literal>''</literal> だけで + 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP + では文字列リテラル中に生の改行が書けるので + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ $a =' a' ;; - ]]> -</programlisting> -<simpara>とすると <literal>$a</literal> は <literal>"\na"</literal> になるのだが、余計な改行が入ってしまう。</simpara> -<simpara>これらの障害をどのように乗り越えるのか、次節から見ていく。</simpara> + ]]> + </programlisting> + <simpara> + とすると <literal>$a</literal> は <literal>"\na"</literal> になるのだが、余計な改行が入ってしまう。 + </simpara> + <simpara> + これらの障害をどのように乗り越えるのか、次節から見ていく。 + </simpara> </section> <section xml:id="_解説"> <title>解説</title> <section xml:id="_普通の_fizzbuzz"> <title>普通の (?) fizzbuzz</title> - <simpara>まずは普通に書くとしよう。</simpara> + <simpara> + まずは普通に書くとしよう。 + </simpara> <programlisting language="php" linenumbering="unnumbered"> <![CDATA[ - <?php + <?php - for ($i = 1; $i < 100; $i++) { - echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"; - } + for ($i = 1; $i < 100; $i++) { + echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"; + } ]]> </programlisting> - <simpara>素直に書いた fizzbuzz - とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。</simpara> -</section> -<section xml:id="_for_の排除"> - <title><literal>for</literal> の排除</title> - <simpara><literal>for</literal> - は、3文字もある長いキーワードである。こんなものは使えない。<literal>array_</literal> - 系の関数を使って、適当に置き換えるとしよう。</simpara> - <programlisting language="php" linenumbering="unnumbered"> - <![CDATA[ - <?php + <simpara> + 素直に書いた fizzbuzz + とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。 + </simpara> + </section> + <section xml:id="_for_の排除"> + <title><literal>for</literal> の排除</title> + <simpara> + <literal>for</literal> + は、3文字もある長いキーワードである。こんなものは使えない。<literal>array_</literal> + 系の関数を使って、適当に置き換えるとしよう。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + <?php $s = range(1, 100); array_walk( $s, - fn($i) => + fn($i) => printf((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), ); - ]]> - </programlisting> -<simpara><literal>array_walk</literal> や <literal>range</literal>、<literal>printf</literal> といった <literal>for</literal> - よりも長いトークンが現れてしまったが、これは次節で直すことにする。なお、<literal>echo</literal> - は文 (statement) であり式 (expression) ではないので、式である <literal>printf</literal> - に置き換えた。</simpara> -</section> -<section xml:id="_関数呼び出しの短縮"> - <title>関数呼び出しの短縮</title> - <simpara><literal>range</literal>、<literal>array_walk</literal>、<literal>printf</literal> - は長すぎるのでどうにかせねばならない。ここで、PHP - の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。</simpara> - <programlisting language="php" linenumbering="unnumbered"> - <![CDATA[ - <?php + ]]> + </programlisting> + <simpara> + <literal>array_walk</literal> や <literal>range</literal>、<literal>printf</literal> といった <literal>for</literal> + よりも長いトークンが現れてしまったが、これは次節で直すことにする。なお、<literal>echo</literal> + は文 (statement) であり式 (expression) ではないので、式である <literal>printf</literal> + に置き換えた。 + </simpara> + </section> + <section xml:id="_関数呼び出しの短縮"> + <title>関数呼び出しの短縮</title> + <simpara> + <literal>range</literal>、<literal>array_walk</literal>、<literal>printf</literal> + は長すぎるのでどうにかせねばならない。ここで、PHP + の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + <?php $r = 'range'; $w = 'array_walk'; @@ -237,332 +275,372 @@ $s = $r(1, 100); $w( $s, - fn($i) => + fn($i) => $p((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), ); - ]]> - </programlisting> -<simpara>これで関数を呼び出している所は短くなった。では、<literal>$r</literal> や <literal>$w</literal> や -<literal>$p</literal>、また <literal>'Fizz'</literal> や <literal>'Buzz'</literal> はどうやって -1行2文字に収めるのか。次のテクニックへ移ろう。</simpara> -</section> -<section xml:id="_余談_php_8_x_で動作しなくてもいいなら"> - <title>余談: PHP 8.x で動作しなくてもいいなら</title> - <simpara>今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。</simpara> - <blockquote> - <itemizedlist> - <listitem>PHP 7.4〜8.1 で動作すること</listitem> - </itemizedlist> - </blockquote> - <simpara>というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という - PHP 7.x までの仕様が利用できる。例えば、 <literal>Fizz</literal> - という文字列が欲しければ、次のようにする。</simpara> -<programlisting language="php" linenumbering="unnumbered"> - <![CDATA[ - $f - =F - .i - .z - .z - ;; - ]]> -</programlisting> -<simpara>こうして簡単に文字列を作れる。なお、この仕様は 7.x -時点でも警告を受けるので、<literal>@</literal> 演算子を使って抑制してやるとよい。</simpara> -<programlisting language="php" linenumbering="unnumbered"> - <![CDATA[ - $f - =@ - F. - @i - .# - @z - .# - @z - ;; - ]]> -</programlisting> -<simpara>むしろ、このことがわかっていたからこそ PHP 8.x -での動作を要件に課したところがある。</simpara> -</section> -<section xml:id="_文字列リテラルの短縮"> - <title>文字列リテラルの短縮</title> - <simpara>実際に使った手法の説明に移る。</simpara> - <simpara>ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 - (<literal>&</literal>、<literal>|</literal>、<literal>^</literal>) - をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。</simpara> -<programlisting language="php" linenumbering="unnumbered"> - <![CDATA[ - $a = "12345"; - $b = "world"; - - // $a ^ $b は次のコードと同じ - $result = ''; - for ($i = 0; $i < min(strlen($a), strlen($b)); $i++) { - $result .= $a[$i] ^ $b[$i]; - } - - echo $result; - // => F]AXQ - ]]> -</programlisting> -<simpara>これを踏まえ、次のコードを見てみよう。</simpara> -<programlisting language="php" linenumbering="unnumbered"> - <![CDATA[ - $x = "x\nOm\n"; - $y = "\nk!\no"; - $r = $x ^ $y; - echo "$r\n"; - ]]> -</programlisting> -<simpara>実行すると、<literal>range</literal> が表示される。さて、PHP -では文字列リテラル中に生の改行を直接書いてもよいのだった -(「主な障害」の節を参照のこと)。書きかえてみよう。</simpara> -<programlisting language="php" linenumbering="unnumbered"> - <![CDATA[ - $x - ='x - Om - '; - $y - =' - k! - o' - ; - - $r = $x ^ $y; - echo "$r\n"; - ]]> -</programlisting> -<simpara>さらに <literal>#</literal> を使って適当に調整すると、次のようになる。</simpara> -<programlisting language="php" linenumbering="unnumbered"> - <![CDATA[ - $x - =# - 'x - Om - '; - $y - =' - k! - o' - ;# - $r - =# - $x - ^# - $y - ;# + ]]> + </programlisting> + <simpara> + これで関数を呼び出している所は短くなった。では、<literal>$r</literal> や <literal>$w</literal> や + <literal>$p</literal>、また <literal>'Fizz'</literal> や <literal>'Buzz'</literal> はどうやって + 1行2文字に収めるのか。次のテクニックへ移ろう。 + </simpara> + </section> + <section xml:id="_余談_php_8_x_で動作しなくてもいいなら"> + <title>余談: PHP 8.x で動作しなくてもいいなら</title> + <simpara> + 今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。 + </simpara> + <blockquote> + <itemizedlist> + <listitem>PHP 7.4〜8.1 で動作すること</listitem> + </itemizedlist> + </blockquote> + <simpara> + というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という + PHP 7.x までの仕様が利用できる。例えば、 <literal>Fizz</literal> + という文字列が欲しければ、次のようにする。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + $f + =F + .i + .z + .z + ;; + ]]> + </programlisting> + <simpara> + こうして簡単に文字列を作れる。なお、この仕様は 7.x + 時点でも警告を受けるので、<literal>@</literal> 演算子を使って抑制してやるとよい。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + $f + =@ + F. + @i + .# + @z + .# + @z + ;; + ]]> + </programlisting> + <simpara> + むしろ、このことがわかっていたからこそ PHP 8.x + での動作を要件に課したところがある。 + </simpara> + </section> + <section xml:id="_文字列リテラルの短縮"> + <title>文字列リテラルの短縮</title> + <simpara> + 実際に使った手法の説明に移る。 + </simpara> + <simpara> + ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 + (<literal>&</literal>、<literal>|</literal>、<literal>^</literal>) + をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + $a = "12345"; + $b = "world"; - echo "$r\n"; - ]]> -</programlisting> -<simpara>1行あたり2文字で、<literal>range</literal> - という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。</simpara> -<simpara>備考: <literal>Buzz</literal> 中にある小文字の <literal>u</literal> は、このロジックだと non-printable -な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。</simpara> -</section> -</section> -<section xml:id="_完成系"> - <title>完成系</title> - <simpara>完成したものがこちら。</simpara> - <programlisting language="php" linenumbering="unnumbered"> - <![CDATA[ - <?php + // $a ^ $b は次のコードと同じ + $result = ''; + for ($i = 0; $i < min(strlen($a), strlen($b)); $i++) { + $result .= $a[$i] ^ $b[$i]; + } + echo $result; + // => F]AXQ + ]]> + </programlisting> + <simpara> + これを踏まえ、次のコードを見てみよう。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + $x = "x\nOm\n"; + $y = "\nk!\no"; + $r = $x ^ $y; + echo "$r\n"; + ]]> + </programlisting> + <simpara> + 実行すると、<literal>range</literal> が表示される。さて、PHP + では文字列リテラル中に生の改行を直接書いてもよいのだった + (「主な障害」の節を参照のこと)。書きかえてみよう。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ $x - =# - 'i - S' - ;; - $y - =' - b! - '; - $c - =# - $x - ^# - $y - ;# - $x - =# - 'x + ='x Om '; $y =' k! o' - ;# - $r - =# - $x - ^# - $y - ;# + ; + + $r = $x ^ $y; + echo "$r\n"; + ]]> + </programlisting> + <simpara> + さらに <literal>#</literal> を使って適当に調整すると、次のようになる。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ $x =# - 'k - Sk - ~} - Ma + 'x + Om '; $y =' - x! - s! k! - '; - $w - =# - $x - ^# - $y - ;# - $x - =# - 'z - Hd - G' - ;# - $y - =' - x! - ~! - '; - $p - =# - $x - ^# - $y - ;# - $x - =# - 'L - [p - '; - $y - =' - c! - '; - $f - =# - $x - ^# - $y + o' ;# - $x - =# - 'H - [p - '; - $y - =' - _! - '; - $b + $r =# $x ^# $y ;# - $b - [1 - ]= - $c - (# - 13 - *9 - ); - $s - =# - $r - (1 - ,( - 10 - ** - 2) - ); - $w - (# - $s - ,# - fn - (# - $i - )# - => - $p - (( - (# - $i - %3 - ?# - '' - :# - $f - ). - (# - $i - %5 - ?# - '' - :# - $b - )? - :# - $i - )# - .' - ') - ); + + echo "$r\n"; + ]]> + </programlisting> + <simpara> + 1行あたり2文字で、<literal>range</literal> + という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。 + </simpara> + <simpara> + 備考: <literal>Buzz</literal> 中にある小文字の <literal>u</literal> は、このロジックだと non-printable + な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。 + </simpara> + </section> +</section> +<section xml:id="_完成系"> + <title>完成系</title> + <simpara> + 完成したものがこちら。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + <?php + + $x + =# + 'i + S' + ;; + $y + =' + b! + '; + $c + =# + $x + ^# + $y + ;# + $x + =# + 'x + Om + '; + $y + =' + k! + o' + ;# + $r + =# + $x + ^# + $y + ;# + $x + =# + 'k + Sk + ~} + Ma + '; + $y + =' + x! + s! + k! + '; + $w + =# + $x + ^# + $y + ;# + $x + =# + 'z + Hd + G' + ;# + $y + =' + x! + ~! + '; + $p + =# + $x + ^# + $y + ;# + $x + =# + 'L + [p + '; + $y + =' + c! + '; + $f + =# + $x + ^# + $y + ;# + $x + =# + 'H + [p + '; + $y + =' + _! + '; + $b + =# + $x + ^# + $y + ;# + $b + [1 + ]= + $c + (# + 13 + *9 + ); + $s + =# + $r + (1 + ,( + 10 + ** + 2) + ); + $w + (# + $s + ,# + fn + (# + $i + )# + => + $p + (( + (# + $i + %3 + ?# + '' + :# + $f + ). + (# + $i + %5 + ?# + '' + :# + $b + )? + :# + $i + )# + .' + ') + ); ]]> </programlisting> </section> <section xml:id="_感想など"> <title>感想など</title> - <simpara>PHP は、スクリプト言語の中だとシンタックスシュガーが少ない - (体感)。この挑戦は不可能に思われたが、PHP - マニュアルとにらめっこしていたらなんとかなった。</simpara> -<simpara>みんなもプログラムを細長くしよう。</simpara> + <simpara> + PHP は、スクリプト言語の中だとシンタックスシュガーが少ない + (体感)。この挑戦は不可能に思われたが、PHP + マニュアルとにらめっこしていたらなんとかなった。 + </simpara> + <simpara> + みんなもプログラムを細長くしよう。 + </simpara> </section> <section xml:id="_余談2_別解"> <title>余談2: 別解</title> - <simpara>PHP では、バッククォートを使ってシェルを呼び出せる。これは <literal>shell_exec</literal> + <simpara> + PHP では、バッククォートを使ってシェルを呼び出せる。これは <literal>shell_exec</literal> 関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash - なら大丈夫だろう。知らんけど)。</simpara> + なら大丈夫だろう。知らんけど)。 + </simpara> <programlisting language="php" linenumbering="unnumbered"> <![CDATA[ - <?php + <?php - printf(` - e\ - c\ - h\ - o\ - \ - 1\ - 2\ - 3\ - `); + printf(` + e\ + c\ + h\ + o\ + \ + 1\ + 2\ + 3\ + `); ]]> </programlisting> -<simpara>なお、ここでは簡単のため出力に <literal>printf</literal> をそのまま使っているが、実際には -<literal>printf</literal> という文字列を合成して可変関数で呼び出す。</simpara> -<simpara>ただし、これでは</simpara> -<blockquote> - <itemizedlist> - <listitem>スペースやタブを使用しないこと</listitem> - </itemizedlist> -</blockquote> -<simpara>に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。</simpara> -<simpara>もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。</simpara> -<programlisting language="php" linenumbering="unnumbered"> - <![CDATA[ - <?php + <simpara> + なお、ここでは簡単のため出力に <literal>printf</literal> をそのまま使っているが、実際には + <literal>printf</literal> という文字列を合成して可変関数で呼び出す。 + </simpara> + <simpara> + ただし、これでは + </simpara> + <blockquote> + <itemizedlist> + <listitem>スペースやタブを使用しないこと</listitem> + </itemizedlist> + </blockquote> + <simpara> + に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。 + </simpara> + <simpara> + もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + <?php $c = 'chr'; @@ -591,20 +669,24 @@ 2\ 3\ `); - ]]> -</programlisting> -<simpara>先程と同じく、<literal>chr</literal> や <literal>printf</literal> を生成する部分は長くなるので省いた。</simpara> -<literallayout class="monospaced"> - <![CDATA[ + ]]> + </programlisting> + <simpara> + 先程と同じく、<literal>chr</literal> や <literal>printf</literal> を生成する部分は長くなるので省いた。 + </simpara> + <literallayout class="monospaced"> + <![CDATA[ ${ '_ '} - ]]> -</literallayout> -<simpara>は変数で、中にはスペースとエスケープが入っている -(<literal>chr(32) . chr(92)</literal>)。シェルに渡されている文字列は次のようになる。</simpara> -<literallayout class="monospaced"> - <![CDATA[ + ]]> + </literallayout> + <simpara> + は変数で、中にはスペースとエスケープが入っている + (<literal>chr(32) . chr(92)</literal>)。シェルに渡されている文字列は次のようになる。 + </simpara> + <literallayout class="monospaced"> + <![CDATA[ e\ c\ h\ @@ -613,20 +695,28 @@ 1\ 2\ 3\ - ]]> -</literallayout> -<simpara>これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz -のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう -(試してないけど)。</simpara> -<simpara>ということでこれは別解ということにしておく。</simpara> -<simpara>ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。</simpara> -<literallayout class="monospaced"> - <![CDATA[ + ]]> + </literallayout> + <simpara> + これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz + のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう + (試してないけど)。 + </simpara> + <simpara> + ということでこれは別解ということにしておく。 + </simpara> + <simpara> + ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。 + </simpara> + <literallayout class="monospaced"> + <![CDATA[ ${ '_ '} - ]]> -</literallayout> -<simpara>最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。</simpara> + ]]> + </literallayout> + <simpara> + 最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。 + </simpara> </section> </article> diff --git a/content/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1.xml b/content/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1.xml index 760582d..f53d339 100644 --- a/content/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1.xml +++ b/content/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1.xml @@ -16,106 +16,180 @@ </revision> </revhistory> </info> - <section xml:id="_はじめに"> + <section xml:id="intro"> <title>はじめに</title> - <simpara>2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) - の、 <link xl:href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</link> - において、昨年と同様に、弊社 <link xl:href="https://www.dgcircus.com/">デジタルサーカス株式会社</link> - から、トークン問題を出題予定である。</simpara> - <simpara>昨年のトークン問題の記事はこちら: - <link xl:href="/posts/2022-04-09/phperkaigi-2022-tokens">PHPerKaigi 2022 - トークン問題の解説</link></simpara> -<simpara>すでに 2023 -年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi -開催を待つ間に紹介しようと思う。</simpara> -<simpara>10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。</simpara> + <simpara> + 2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) + の、 <link xl:href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</link> + において、昨年と同様に、弊社 <link xl:href="https://www.dgcircus.com/">デジタルサーカス株式会社</link> + から、トークン問題を出題予定である。 + </simpara> + <simpara> + 昨年のトークン問題の記事はこちら: + <link xl:href="/posts/2022-04-09/phperkaigi-2022-tokens">PHPerKaigi 2022 + トークン問題の解説</link> + </simpara> + <simpara> + すでに 2023 + 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi + 開催を待つ間に紹介しようと思う。 + </simpara> + <simpara> + 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。 + </simpara> </section> -<section xml:id="_問題"> +<section xml:id="quiz"> <title>問題</title> - <simpara>注意: これはボツ問なので、得られたトークンを PHPerKaigi - で入力してもポイントにはならない。</simpara> -<programlisting language="php" linenumbering="unnumbered"><?php + <simpara> + 注意: これはボツ問なので、得られたトークンを PHPerKaigi + で入力してもポイントにはならない。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + <?php -$π = $argv[1] ?? null; -if ($π === null) { -exit('No input.'); -} -$π = trim($π); -if (!is_numeric($π)) { -exit('Invalid input.'); -} + $π = $argv[1] ?? null; + if ($π === null) { + exit('No input.'); + } + $π = trim($π); + if (!is_numeric($π)) { + exit('Invalid input.'); + } -$s = implode(array_map(chr(...), str_split($π, 2))); + $s = implode(array_map(chr(...), str_split($π, 2))); -preg_match('/(\x23.+?) /', $s, $m); -$t = $m[1] ?? ''; + preg_match('/(\x23.+?) /', $s, $m); + $t = $m[1] ?? ''; -if (md5($t) === '056e831a4146bf123e8ea16613303d2e') { -echo "Token: {$t}\n"; -} else { -echo "Failed.\n"; -}</programlisting> + if (md5($t) === '056e831a4146bf123e8ea16613303d2e') { + echo "Token: {$t}\n"; + } else { + echo "Failed.\n"; + } + ]]> + </programlisting> </section> -<section xml:id="_トークン入手方法"> +<section xml:id="how-to-obtain-token"> <title>トークン入手方法</title> - <simpara>ソースを見るとわかるとおり、<literal>$argv[1]</literal> を参照している。それを <literal>$π</literal> - なる変数に代入しているので、円周率を渡してみる。</simpara> - <programlisting language="shell-session" linenumbering="unnumbered">$ php Q.php 3.14 - Failed.</programlisting> -<simpara>失敗してしまった。精度を上げてみる。</simpara> -<programlisting language="shell-session" linenumbering="unnumbered">$ php Q.php 3.1415 -Failed.</programlisting> -<simpara>だめだった。これを成功するまで繰り返す。</simpara> -<simpara>最初にトークンが得られるのは、小数点以下 16 -桁目まで入力したときで、こうなる。</simpara> -<programlisting language="shell-session" linenumbering="unnumbered">$ php Q.php 3.1415926535897932 -Token: #YO</programlisting> -<simpara>めでたくトークン「#YO」が手に入った。</simpara> + <simpara> + ソースを見るとわかるとおり、<literal>$argv[1]</literal> を参照している。それを <literal>$π</literal> + なる変数に代入しているので、円周率を渡してみる。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ php Q.php 3.14 + Failed. + ]]> + </programlisting> + <simpara> + 失敗してしまった。精度を上げてみる。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ php Q.php 3.1415 + Failed. + ]]> + </programlisting> + <simpara> + だめだった。これを成功するまで繰り返す。 + </simpara> + <simpara> + 最初にトークンが得られるのは、小数点以下 16 + 桁目まで入力したときで、こうなる。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ php Q.php 3.1415926535897932 + Token: #YO + ]]> + </programlisting> + <simpara> + めでたくトークン「<literal>#YO</literal>」が手に入った。 + </simpara> </section> -<section xml:id="_解説"> +<section xml:id="commentary"> <title>解説</title> - <simpara>短いので頭から追っていく。</simpara> - <programlisting language="php" linenumbering="unnumbered">$π = $argv[1] ?? null; - if ($π === null) { - exit('No input.'); - } - $π = trim($π); - if (!is_numeric($π)) { - exit('Invalid input.'); - }</programlisting> -<simpara>入力のバリデーション部分。数値のみ受け付ける。</simpara> -<programlisting language="php" linenumbering="unnumbered">$s = implode(array_map(chr(...), str_split($π, 2)));</programlisting> -<simpara><literal>$π</literal> を 2 文字ごとに区切り (<literal>str_split</literal>)、数値を ASCII -コードと見做して文字に変換 (<literal>chr</literal>) して結合 (<literal>implode</literal>) している。</simpara> -<simpara>例えば、<literal>$π</literal> が <literal>'656667'</literal> だったとすると、<literal>65</literal>、<literal>66</literal>、<literal>67</literal> に対応した -<literal>'A'</literal>、<literal>'B'</literal>、<literal>'C'</literal> へと変換され、<literal>'ABC'</literal> になる。</simpara> -<programlisting language="php" linenumbering="unnumbered">$π = '656667'; -$s = implode(array_map(chr(...), str_split($π, 2))); -echo $s; -// => ABC</programlisting> -<programlisting language="php" linenumbering="unnumbered">preg_match('/(\x23.+?) /', $s, $m); -$t = $m[1] ?? '';</programlisting> -<simpara>正規表現でマッチングしている。<literal>\x23</literal> は <literal>#</literal> - と同じであることに留意すると、この正規表現は「<literal>#</literal> から始まる 2 - 以上の長さ (含 <literal>#</literal>) - の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi - におけるトークンである。</simpara> -<simpara>なお、<literal>#</literal> を直接書いていないのは、<literal>/#.+?) /</literal> と書くと、<literal>#.+?)</literal> - という意図せぬトークンが登録されてしまうからである。</simpara> -<programlisting language="php" linenumbering="unnumbered">if (md5($t) === '056e831a4146bf123e8ea16613303d2e') { -echo "Token: {$t}\n"; -} else { -echo "Failed.\n"; -}</programlisting> -<simpara>最後にトークンのハッシュ値を見て、想定解かどうかを確認する。</simpara> + <simpara> + 短いので頭から追っていく。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + $π = $argv[1] ?? null; + if ($π === null) { + exit('No input.'); + } + $π = trim($π); + if (!is_numeric($π)) { + exit('Invalid input.'); + } + ]]> + </programlisting> + <simpara> + 入力のバリデーション部分。数値のみ受け付ける。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + $s = implode(array_map(chr(...), str_split($π, 2))); + ]]> + </programlisting> + <simpara> + <literal>$π</literal> を 2 文字ごとに区切り (<literal>str_split</literal>)、数値を ASCII + コードと見做して文字に変換 (<literal>chr</literal>) して結合 (<literal>implode</literal>) している。 + </simpara> + <simpara> + 例えば、<literal>$π</literal> が <literal>'656667'</literal> だったとすると、<literal>65</literal>、<literal>66</literal>、<literal>67</literal> に対応した + <literal>'A'</literal>、<literal>'B'</literal>、<literal>'C'</literal> へと変換され、<literal>'ABC'</literal> になる。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + $π = '656667'; + $s = implode(array_map(chr(...), str_split($π, 2))); + echo $s; + // => ABC + ]]> + </programlisting> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + preg_match('/(\x23.+?) /', $s, $m); + $t = $m[1] ?? ''; + ]]> + </programlisting> + <simpara> + 正規表現でマッチングしている。<literal>\x23</literal> は <literal>#</literal> + と同じであることに留意すると、この正規表現は「<literal>#</literal> から始まる 2 + 以上の長さ (含 <literal>#</literal>) + の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi + におけるトークンである。 + </simpara> + <simpara> + なお、<literal>#</literal> を直接書いていないのは、<literal>/#.+?) /</literal> と書くと、<literal>#.+?)</literal> + という意図せぬトークンが登録されてしまうからである。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + if (md5($t) === '056e831a4146bf123e8ea16613303d2e') { + echo "Token: {$t}\n"; + } else { + echo "Failed.\n"; + } + ]]> + </programlisting> + <simpara> + 最後にトークンのハッシュ値を見て、想定解かどうかを確認する。 + </simpara> </section> -<section xml:id="_おわりに"> +<section xml:id="outro"> <title>おわりに</title> - <simpara>円周率を何桁も計算して ASCII - コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。</simpara> -<simpara>最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた -(ちなみに、それでも <literal>M_PI</literal> や <literal>pi()</literal> -では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 -万桁目くらいに埋まっていてくれたほうがよかったかもしれない。</simpara> + <simpara> + 円周率を何桁も計算して ASCII + コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。 + </simpara> + <simpara> + 最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた + (ちなみに、それでも <literal>M_PI</literal> や <literal>pi()</literal> + では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 + 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。 + </simpara> </section> </article> diff --git a/content/posts/2022-10-28/setup-server-for-this-site.xml b/content/posts/2022-10-28/setup-server-for-this-site.xml index 388238b..b388b36 100644 --- a/content/posts/2022-10-28/setup-server-for-this-site.xml +++ b/content/posts/2022-10-28/setup-server-for-this-site.xml @@ -15,171 +15,294 @@ </revision> </revhistory> </info> - <section xml:id="_はじめに"> + <section xml:id="intro"> <title>はじめに</title> - <simpara>これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS - に移行した。そのときにおこなったサーバのセットアップ作業を書き残しておく。99 - % 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。</simpara> - <simpara>未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。</simpara> -</section> -<section xml:id="_vps"> - <title>VPS</title> - <simpara><link xl:href="https://vps.sakura.ad.jp/">さくらの VPS</link> の 2 GB - プラン。そこまで真面目に選定していないので、困ったら移動するかも。</simpara> -</section> -<section xml:id="_事前準備"> - <title>事前準備</title> - <section xml:id="_サーバのホスト名を決める"> - <title>サーバのホスト名を決める</title> - <simpara>モチベーションが上がるという効能がある。今回は藤原定家から取って - ``teika'' - にした。たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。</simpara> -</section> -<section xml:id="_ssh_の鍵生成"> - <title>SSH の鍵生成</title> - <simpara>ローカルマシンで鍵を生成する。</simpara> - <programlisting language="shell-session" linenumbering="unnumbered">$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/teika.key - $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key</programlisting> -<simpara><literal>teika.key</literal> はローカルからサーバへの接続用、<literal>github2teika.key</literal> - は、GitHub Actions からサーバへのデプロイ用。</simpara> -</section> -<section xml:id="_ssh_の設定"> - <title>SSH の設定</title> - <simpara><literal>.ssh/config</literal> に設定しておく。</simpara> - <programlisting language="ssh_config" linenumbering="unnumbered">Host teika - HostName ********** - User ********** - Port ********** - IdentityFile ~/.ssh/teika.key</programlisting> -</section> -</section> -<section xml:id="_基本のセットアップ"> - <title>基本のセットアップ</title> - <section xml:id="_ssh_接続"> - <title>SSH 接続</title> - <simpara>VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。</simpara> + <simpara> + これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS に移行した。 + そのときにおこなったサーバのセットアップ作業を書き残しておく。 + 99 % 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。 + </simpara> + <simpara> + 未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。 + </simpara> </section> - <section xml:id="_ユーザを作成する"> - <title>ユーザを作成する</title> - <simpara>管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。<literal>sudo</literal> - グループに追加して <literal>sudo</literal> できるようにし、<literal>su</literal> で切り替え。</simpara> - <programlisting language="shell-session" linenumbering="unnumbered">$ sudo adduser ********** - $ sudo adduser ********** sudo - $ su ********** - $ cd</programlisting> -</section> -<section xml:id="_ホスト名を変える"> - <title>ホスト名を変える</title> - <programlisting language="shell-session" linenumbering="unnumbered">$ sudo hostname teika</programlisting> -</section> -<section xml:id="_公開鍵を置く"> - <title>公開鍵を置く</title> - <programlisting language="shell-session" linenumbering="unnumbered">$ mkdir ~/.ssh - $ chmod 700 ~/.ssh - $ vi ~/.ssh/authorized_keys</programlisting> -<simpara><literal>authorized_keys</literal> には、ローカルで生成した <literal>~/.ssh/teika.key.pub</literal> と -<literal>~/.ssh/github2teika.key.pub</literal> の内容をコピーする。</simpara> -</section> -<section xml:id="_ssh_の設定_2"> - <title>SSH の設定</title> - <simpara>SSH の設定を変更し、少しでも安全にしておく。</simpara> - <programlisting language="shell-session" linenumbering="unnumbered">$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak - $ sudo vi /etc/ssh/sshd_config</programlisting> -<itemizedlist> - <listitem><literal>Port</literal> を変更</listitem> - <listitem><literal>PermitRootLogin</literal> を <literal>no</literal> に</listitem> - <listitem><literal>PasswordAuthentication</literal> を <literal>no</literal> に</listitem> -</itemizedlist> -<simpara>そして設定を反映。</simpara> -<programlisting language="shell-session" linenumbering="unnumbered">$ sudo systemctl restart sshd -$ sudo systemctl status sshd</programlisting> -</section> -<section xml:id="_ssh_で接続確認"> - <title>SSH で接続確認</title> - <simpara>今の SSH - セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH - の設定に不備があった場合に締め出しをくらう。</simpara> -<programlisting language="shell-session" linenumbering="unnumbered">$ ssh teika</programlisting> -</section> -<section xml:id="_ポートの遮断"> - <title>ポートの遮断</title> - <simpara>デフォルトの 22 番を閉じ、設定したポートだけ空ける。</simpara> - <programlisting language="shell-session" linenumbering="unnumbered">$ sudo ufw deny ssh - $ sudo ufw allow ******* - $ sudo ufw enable - $ sudo ufw reload - $ sudo ufw status</programlisting> -<simpara>ここでもう一度 SSH の接続確認を挟む。</simpara> -</section> -<section xml:id="_github_用の_ssh_鍵"> - <title>GitHub 用の SSH 鍵</title> - <simpara>GitHub に置いてある private リポジトリをサーバから clone したいので、SSH - 鍵を生成して置いておく。</simpara> -<programlisting language="shell-session" linenumbering="unnumbered">$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github.key -$ cat ~/.ssh/github.key.pub</programlisting> -<simpara><link xl:href="https://github.com/settings/ssh">GitHub の設定画面</link> - から、この公開鍵を追加する。</simpara> -<programlisting language="shell-session" linenumbering="unnumbered">$ vi ~/.ssh/config</programlisting> -<simpara>設定はこう。</simpara> -<programlisting language="ssh_config" linenumbering="unnumbered">Host github.com -HostName github.com -User git -IdentityFile ~/.ssh/github.key</programlisting> -<simpara>最後に接続できるか確認しておく。</simpara> -<programlisting language="shell-session" linenumbering="unnumbered">ssh -T github.com</programlisting> -</section> -<section xml:id="_パッケージの更新"> - <title>パッケージの更新</title> - <programlisting language="shell-session" linenumbering="unnumbered">$ sudo apt update - $ sudo apt upgrade - $ sudo apt update - $ sudo apt upgrade - $ sudo apt autoremove</programlisting> -</section> -</section> -<section xml:id="_サイトホスティング用のセットアップ"> - <title>サイトホスティング用のセットアップ</title> - <section xml:id="_dns_に_ip_アドレスを登録する"> - <title>DNS に IP アドレスを登録する</title> - <simpara>このサーバは固定の IP アドレスがあるので、<literal>A</literal> - レコードに直接入れるだけで済んだ。</simpara> + <section xml:id="vps"> + <title>VPS</title> + <simpara> + <link xl:href="https://vps.sakura.ad.jp/">さくらの VPS</link> の 2 GB プラン。 + そこまで真面目に選定していないので、困ったら移動するかも。 + </simpara> </section> - <section xml:id="_使うソフトウェアのインストール"> - <title>使うソフトウェアのインストール</title> - <programlisting language="shell-session" linenumbering="unnumbered">$ sudo apt install docker docker-compose git make</programlisting> + <section xml:id="preparation"> + <title>事前準備</title> + <section xml:id="preparation--hostname"> + <title>サーバのホスト名を決める</title> + <simpara> + モチベーションが上がるという効能がある。今回は藤原定家から取って <literal>teika</literal> にした。 + たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。 + </simpara> + </section> + <section xml:id="preparation--ssh-key"> + <title>SSH の鍵生成</title> + <simpara> + ローカルマシンで鍵を生成する。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/teika.key + $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key + ]]> + </programlisting> + <simpara> + <literal>teika.key</literal> はローカルからサーバへの接続用、<literal>github2teika.key</literal> + は、GitHub Actions からサーバへのデプロイ用。 + </simpara> + </section> + <section xml:id="preparation--ssh-config"> + <title>SSH の設定</title> + <simpara> + <literal>.ssh/config</literal> に設定しておく。 + </simpara> + <programlisting language="ssh_config" linenumbering="unnumbered"> + <![CDATA[ + Host teika + HostName ********** + User ********** + Port ********** + IdentityFile ~/.ssh/teika.key + ]]> + </programlisting> + </section> </section> - <section xml:id="_メインユーザが_docker_を使えるように"> - <title>メインユーザが Docker を使えるように</title> - <programlisting language="shell-session" linenumbering="unnumbered">sudo adduser ********** docker</programlisting> + <section xml:id="basic-setup"> + <title>基本のセットアップ</title> + <section xml:id="basic-setup--login"> + <title>SSH 接続</title> + <simpara> + VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。 + </simpara> + </section> + <section xml:id="basic-setup--user"> + <title>ユーザを作成する</title> + <simpara> + 管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。<literal>sudo</literal> + グループに追加して <literal>sudo</literal> できるようにし、<literal>su</literal> で切り替え。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ sudo adduser ********** + $ sudo adduser ********** sudo + $ su ********** + $ cd + ]]> + </programlisting> + </section> + <section xml:id="basic-setup--hostname"> + <title>ホスト名を変える</title> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ sudo hostname teika + ]]> + </programlisting> + </section> + <section xml:id="basic-setup--public-key"> + <title>公開鍵を置く</title> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ mkdir ~/.ssh + $ chmod 700 ~/.ssh + $ vi ~/.ssh/authorized_keys + ]]> + </programlisting> + <simpara> + <literal>authorized_keys</literal> には、ローカルで生成した <literal>~/.ssh/teika.key.pub</literal> と + <literal>~/.ssh/github2teika.key.pub</literal> の内容をコピーする。 + </simpara> + </section> + <section xml:id="basic-setup--ssh-config"> + <title>SSH の設定</title> + <simpara> + SSH の設定を変更し、少しでも安全にしておく。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak + $ sudo vi /etc/ssh/sshd_config + ]]> + </programlisting> + <itemizedlist> + <listitem><literal>Port</literal> を変更</listitem> + <listitem><literal>PermitRootLogin</literal> を <literal>no</literal> に</listitem> + <listitem><literal>PasswordAuthentication</literal> を <literal>no</literal> に</listitem> + </itemizedlist> + <simpara> + そして設定を反映。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ sudo systemctl restart sshd + $ sudo systemctl status sshd + ]]> + </programlisting> + </section> + <section xml:id="basic-setup--ssh-connect"> + <title>SSH で接続確認</title> + <simpara> + 今の SSH + セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH + の設定に不備があった場合に締め出しをくらう。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ ssh teika + ]]> + </programlisting> + </section> + <section xml:id="basic-setup--close-ports"> + <title>ポートの遮断</title> + <simpara> + デフォルトの 22 番を閉じ、設定したポートだけ空ける。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ sudo ufw deny ssh + $ sudo ufw allow ******* + $ sudo ufw enable + $ sudo ufw reload + $ sudo ufw status + ]]> + </programlisting> + <simpara> + ここでもう一度 SSH の接続確認を挟む。 + </simpara> + </section> + <section xml:id="basic-setup--ssh-key-for-github"> + <title>GitHub 用の SSH 鍵</title> + <simpara> + GitHub に置いてある private リポジトリをサーバから clone したいので、SSH + 鍵を生成して置いておく。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github.key + $ cat ~/.ssh/github.key.pub + ]]> + </programlisting> + <simpara> + <link xl:href="https://github.com/settings/ssh">GitHub の設定画面</link> + から、この公開鍵を追加する。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ vi ~/.ssh/config + ]]> + </programlisting> + <simpara> + 設定はこう。 + </simpara> + <programlisting language="ssh_config" linenumbering="unnumbered"> + <![CDATA[ + Host github.com + HostName github.com + User git + IdentityFile ~/.ssh/github.key + ]]> + </programlisting> + <simpara> + 最後に接続できるか確認しておく。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + ssh -T github.com + ]]> + </programlisting> + </section> + <section xml:id="basic-setup--upgrade-packages"> + <title>パッケージの更新</title> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ sudo apt update + $ sudo apt upgrade + $ sudo apt update + $ sudo apt upgrade + $ sudo apt autoremove + ]]> + </programlisting> + </section> + </section> + <section xml:id="site-hosting-setup"> + <title>サイトホスティング用のセットアップ</title> + <section xml:id="site-hosting-setup--dns"> + <title>DNS に IP アドレスを登録する</title> + <simpara> + このサーバは固定の IP アドレスがあるので、<literal>A</literal> + レコードに直接入れるだけで済んだ。 + </simpara> + </section> + <section xml:id="site-hosting-setup--install-softwares"> + <title>使うソフトウェアのインストール</title> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ sudo apt install docker docker-compose git make + ]]> + </programlisting> + </section> + <section xml:id="site-hosting-setup--docker"> + <title>メインユーザが Docker を使えるように</title> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + sudo adduser ********** docker + ]]> + </programlisting> + </section> + <section xml:id="site-hosting-setup--open-http-ports"> + <title>HTTP/HTTPS を通す</title> + <simpara> + 80 番と 443 番を空ける。 + </simpara> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ sudo ufw allow 80/tcp + $ sudo ufw allow 443/tcp + $ sudo ufw reload + $ sudo ufw status + ]]> + </programlisting> + </section> + <section xml:id="site-hosting-setup--clone-repositories"> + <title>リポジトリのクローン</title> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ cd + $ git clone git@github.com:nsfisis/nsfisis.dev.git + $ cd nsfisis.dev + $ git submodule update --init + ]]> + </programlisting> + </section> + <section xml:id="site-hosting-setup--certbot"> + <title>certbot で証明書取得</title> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ docker-compose up -d acme-challenge + $ make setup + ]]> + </programlisting> + </section> + <section xml:id="site-hosting-setup--run-server"> + <title>サーバを稼動させる</title> + <programlisting language="shell-session" linenumbering="unnumbered"> + <![CDATA[ + $ make serve + ]]> + </programlisting> + </section> + </section> + <section xml:id="outro"> + <title>感想</title> + <simpara> + (業務でなく) + 個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。 + </simpara> </section> - <section xml:id="_httphttps_を通す"> - <title>HTTP/HTTPS を通す</title> - <simpara>80 番と 443 番を空ける。</simpara> - <programlisting language="shell-session" linenumbering="unnumbered">$ sudo ufw allow 80/tcp - $ sudo ufw allow 443/tcp - $ sudo ufw reload - $ sudo ufw status</programlisting> -</section> -<section xml:id="_リポジトリのクローン"> - <title>リポジトリのクローン</title> - <programlisting language="shell-session" linenumbering="unnumbered">$ cd - $ git clone git@github.com:nsfisis/nsfisis.dev.git - $ cd nsfisis.dev - $ git submodule update --init</programlisting> -</section> -<section xml:id="_certbot_で証明書取得"> - <title>certbot で証明書取得</title> - <programlisting language="shell-session" linenumbering="unnumbered">$ docker-compose up -d acme-challenge - $ make setup</programlisting> -</section> -<section xml:id="_サーバを稼動させる"> - <title>サーバを稼動させる</title> - <programlisting language="shell-session" linenumbering="unnumbered">$ make serve</programlisting> -</section> -</section> -<section xml:id="_感想"> - <title>感想</title> - <simpara>(業務でなく) - 個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。</simpara> -</section> </article> diff --git a/content/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2.xml b/content/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2.xml index f1df049..b02cb14 100644 --- a/content/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2.xml +++ b/content/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2.xml @@ -16,101 +16,159 @@ </revision> </revhistory> </info> - <section xml:id="_はじめに"> + <section xml:id="intro"> <title>はじめに</title> - <simpara>2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の <link xl:href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</link> において、 - 昨年と同様に、弊社 <link xl:href="https://www.dgcircus.com/">デジタルサーカス株式会社</link> からトークン問題を出題予定である。</simpara> - <simpara>昨年のトークン問題の記事はこちら: <link xl:href="/posts/2022-04-09/phperkaigi-2022-tokens/">PHPerKaigi 2022 トークン問題の解説</link></simpara> - <simpara>すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。</simpara> - <simpara>10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。</simpara> - <simpara>その 1 はこちら: <link xl:href="/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/">PHPerKaigi 2023: ボツになったトークン問題 その 1</link></simpara> -</section> -<section xml:id="_問題"> - <title>問題</title> - <simpara>注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。</simpara> - <programlisting language="php" linenumbering="unnumbered"> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - </programlisting> -<simpara>"And Then There Were None" (そして誰もいなくなった) と名付けた作品。変則 quine (自分自身と同じソースコードを出力するプログラム) になっている。</simpara> -</section> -<section xml:id="_トークン入手方法"> - <title>トークン入手方法</title> - <simpara>実行してみると、次のような出力が得られる。</simpara> - <programlisting language="php" linenumbering="unnumbered"> - # - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - </programlisting> -<simpara>1 行目を除き、先ほどのコードとほぼ同じものが出てきた。もう一度実行してみる。</simpara> -<programlisting language="php" linenumbering="unnumbered"> - # -W -<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> -<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> -<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> -<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> -<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> -<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> -<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> -</programlisting> -<simpara>今度は 2 行目が書き換えられた。すべての行が変化するまで繰り返すと次のようになる。</simpara> -<programlisting language="php" linenumbering="unnumbered"> - # - W - E - L - O - V - E - P - H - P -</programlisting> -<simpara>トークン「#WELOVEPHP」が手に入った。</simpara> -</section> -<section xml:id="_解説"> - <title>解説</title> - <simpara>一見すると同じ行が 10 行並んでいるだけなのにも関わらず、なぜそれぞれの行で出力が変わるのか。ソースコードをコピーして、適当なエディタに貼り付けるとわかりやすい。</simpara> - <simpara>Vim で開くと次のようになる (1 行目を抜粋)。</simpara> - <programlisting language="php" linenumbering="unnumbered"> - <?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - </programlisting> - <simpara><literal><200b></literal> と表示されているのは、Unicode の U+200b で、ゼロ幅スペースである。</simpara> - <note> - <simpara>エディタによっては、ゼロ幅スペースが見えないことがある。VSCode ではブラウザと同様に不可視だった。</simpara> - </note> - <simpara>文字列リテラルの中にゼロ幅スペースを仕込むことで、見た目を変えずに情報をエンコードすることが可能となる。</simpara> - <simpara>続いて、トークンへの変換ロジックを解析する。注目すべきはこの部分だ。以下、ゼロ幅スペースは Vim での表示に合わせて <literal><200b></literal> と記載する。</simpara> - <programlisting language="php" linenumbering="unnumbered"> - fn($s)=>chr(strlen($s)/3) - </programlisting> - <simpara>PHP の <literal>strlen()</literal> は文字列のバイト数を返す。1 行目の <literal>$s</literal> は以下の内容となっており、</simpara> - <programlisting language="php" linenumbering="unnumbered"> - $s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>' - </programlisting> - <simpara>このソースコードは UTF-8 で書かれているので、105 バイトになる。それを 3 で割ると 35 となり、これは <literal>#</literal> の ASCII コードと一致する。他の行も、同様にしてゼロ幅スペースを詰めることで文字列長を調整し、トークンをエンコードしている。</simpara> - <simpara>デコード部以外の部分は、quine のための記述である。</simpara> -</section> -<section xml:id="_おわりに"> - <title>おわりに</title> - <simpara><link xl:href="https://blog.rust-lang.org/2021/11/01/cve-2021-42574.html">CVE-2021-42574</link> に着想を得た作品。この脆弱性は、Unicode の制御文字である left-to-right mark と right-to-left mark を利用し、ソースコードの実際の内容を欺く、というもの。簡単のためゼロ幅スペースを用いることとし、ついでに quine にもするとこうなった。</simpara> - <simpara>ボツになった理由は、ゼロ幅スペースを表示してくるエディタが想像以上に多かったため。「同じ行が並んでいるだけなのに出力が異なる」というアイデアの根幹を崩されてしまうので、この問題は不採用となった。</simpara> -</section> + <simpara> + 2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の <link xl:href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</link> において、 + 昨年と同様に、弊社 <link xl:href="https://www.dgcircus.com/">デジタルサーカス株式会社</link> からトークン問題を出題予定である。 + </simpara> + <simpara> + 昨年のトークン問題の記事はこちら: <link xl:href="/posts/2022-04-09/phperkaigi-2022-tokens/">PHPerKaigi 2022 トークン問題の解説</link> + </simpara> + <simpara> + すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。 + </simpara> + <simpara> + 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。 + </simpara> + <simpara> + その 1 はこちら: <link xl:href="/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/">PHPerKaigi 2023: ボツになったトークン問題 その 1</link> + </simpara> + </section> + <section xml:id="quiz"> + <title>問題</title> + <simpara> + 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + ]]> + </programlisting> + <simpara> + "And Then There Were None" (そして誰もいなくなった) と名付けた作品。変則 quine (自分自身と同じソースコードを出力するプログラム) になっている。 + </simpara> + </section> + <section xml:id="how-to-obtain-token"> + <title>トークン入手方法</title> + <simpara> + 実行してみると、次のような出力が得られる。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + # + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + ]]> + </programlisting> + <simpara> + 1 行目を除き、先ほどのコードとほぼ同じものが出てきた。もう一度実行してみる。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + # + W + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + ]]> + </programlisting> + <simpara> + 今度は 2 行目が書き換えられた。すべての行が変化するまで繰り返すと次のようになる。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + # + W + E + L + O + V + E + P + H + P + ]]> + </programlisting> + <simpara> + トークン「#WELOVEPHP」が手に入った。 + </simpara> + </section> + <section xml:id="commentary"> + <title>解説</title> + <simpara> + 一見すると同じ行が 10 行並んでいるだけなのにも関わらず、なぜそれぞれの行で出力が変わるのか。ソースコードをコピーして、適当なエディタに貼り付けるとわかりやすい。 + </simpara> + <simpara> + Vim で開くと次のようになる (1 行目を抜粋)。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + <?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + ]]> + </programlisting> + <simpara> + <literal><200b></literal> と表示されているのは、Unicode の U+200b で、ゼロ幅スペースである。 + </simpara> + <note> + <simpara> + エディタによっては、ゼロ幅スペースが見えないことがある。VSCode ではブラウザと同様に不可視だった。 + </simpara> + </note> + <simpara> + 文字列リテラルの中にゼロ幅スペースを仕込むことで、見た目を変えずに情報をエンコードすることが可能となる。 + </simpara> + <simpara> + 続いて、トークンへの変換ロジックを解析する。注目すべきはこの部分だ。以下、ゼロ幅スペースは Vim での表示に合わせて <literal><200b></literal> と記載する。 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + fn($s)=>chr(strlen($s)/3) + ]]> + </programlisting> + <simpara> + PHP の <literal>strlen()</literal> は文字列のバイト数を返す。1 行目の <literal>$s</literal> は以下の内容となっており、 + </simpara> + <programlisting language="php" linenumbering="unnumbered"> + <![CDATA[ + $s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>' + ]]> + </programlisting> + <simpara> + このソースコードは UTF-8 で書かれているので、105 バイトになる。それを 3 で割ると 35 となり、これは <literal>#</literal> の ASCII コードと一致する。他の行も、同様にしてゼロ幅スペースを詰めることで文字列長を調整し、トークンをエンコードしている。 + </simpara> + <simpara> + デコード部以外の部分は、quine のための記述である。 + </simpara> + </section> + <section xml:id="outro"> + <title>おわりに</title> + <simpara> + <link xl:href="https://blog.rust-lang.org/2021/11/01/cve-2021-42574.html">CVE-2021-42574</link> に着想を得た作品。この脆弱性は、Unicode の制御文字である left-to-right mark と right-to-left mark を利用し、ソースコードの実際の内容を欺く、というもの。簡単のためゼロ幅スペースを用いることとし、ついでに quine にもするとこうなった。 + </simpara> + <simpara> + ボツになった理由は、ゼロ幅スペースを表示してくるエディタが想像以上に多かったため。「同じ行が並んでいるだけなのに出力が異なる」というアイデアの根幹を崩されてしまうので、この問題は不採用となった。 + </simpara> + </section> </article> diff --git a/content/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3.xml b/content/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3.xml index 6356597..e3eb845 100644 --- a/content/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3.xml +++ b/content/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3.xml @@ -44,24 +44,24 @@ </simpara> <programlisting language="php" linenumbering="unnumbered"> <![CDATA[ - <?php + <?php + try { + f(g() / __LINE__); + } catch (Throwable $e) { + while ($e = $e->getPrevious()) printf('%c', $e->getLine() + 23); + echo "\n"; + } + function f(int $i) { + if ($i < 0) f(); try { - f(g() / __LINE__); - } catch (Throwable $e) { - while ($e = $e->getPrevious()) printf('%c', $e->getLine() + 23); - echo "\n"; - } - function f(int $i) { - if ($i < 0) f(); - try { - match ($i) { - 0 => 0 / 0, + match ($i) { + 0 => 0 / 0, - 15, 36 => 0 / 0, - 14 => 0 / 0, - 37 => 0 / 0, + 15, 36 => 0 / 0, + 14 => 0 / 0, + 37 => 0 / 0, @@ -72,16 +72,16 @@ - 6 => 0 / 0, + 6 => 0 / 0, - 5 => 0 / 0, + 5 => 0 / 0, - 22 => 0 / 0, + 22 => 0 / 0, - 34, 35 => 0 / 0, + 34, 35 => 0 / 0, @@ -90,10 +90,10 @@ - 25 => 0 / 0, - 17, 21 => 0 / 0, + 25 => 0 / 0, + 17, 21 => 0 / 0, - 24, 32 => 0 / 0, + 24, 32 => 0 / 0, @@ -101,12 +101,12 @@ - 33 => 0 / 0, + 33 => 0 / 0, - 16 => 0 / 0, + 16 => 0 / 0, - 18 => 0 / 0, + 18 => 0 / 0, @@ -115,37 +115,37 @@ - 7 => 0 / 0, + 7 => 0 / 0, - 2 => 0 / 0, - 1, 20 => 0 / 0, - 10, 28 => 0 / 0, - 8, 12, 26 => 0 / 0, - 4, 9, 13 => 0 / 0, + 2 => 0 / 0, + 1, 20 => 0 / 0, + 10, 28 => 0 / 0, + 8, 12, 26 => 0 / 0, + 4, 9, 13 => 0 / 0, - 31 => 0 / 0, + 31 => 0 / 0, - 29 => 0 / 0, + 29 => 0 / 0, - 11 => 0 / 0, + 11 => 0 / 0, - 3, 19, 23 => 0 / 0, + 3, 19, 23 => 0 / 0, - 27 => 0 / 0, + 27 => 0 / 0, - 30 => 0 / 0, - }; - } finally { - f($i - 1); - } + 30 => 0 / 0, + }; + } finally { + f($i - 1); } + } @@ -153,9 +153,9 @@ - function g() { - return __LINE__; - } + function g() { + return __LINE__; + } ]]> </programlisting> <simpara> @@ -165,15 +165,15 @@ トークンは PHP の式になっていて、評価すると <literal>Hello, World!</literal> という文字列になる。PHPer チャレンジのトークンには空白を含められないという制約があるが、こういった形でトークンにすれば回避できる。 </simpara> </section> - <section xml:id="_解説"> + <section xml:id="commentary"> <title>解説</title> - <section xml:id="_概要"> + <section xml:id="commentary--summary"> <title>概要</title> <simpara> 例外が発生した行数にデータをエンコードし、それを <literal>catch</literal> で捕まえて表示している。 </simpara> </section> - <section xml:id="_例外オブジェクトの連鎖"> + <section xml:id="commentary--chain-of-exceptions"> <title>例外オブジェクトの連鎖</title> <simpara> <link xl:href="https://www.php.net/class.Exception"><literal>Exception</literal></link> や <link xl:href="https://www.php.net/class.Error"><literal>Error</literal></link> には <literal>$previous</literal> というプロパティがあり、コンストラクタの第3引数から渡すことができる。主に 2つの用法がある: @@ -187,42 +187,42 @@ </simpara> <programlisting language="php" linenumbering="unnumbered"> <![CDATA[ - <?php + <?php + try { try { - try { - throw new Exception("Error 1"); - } finally { - throw new Exception("Error 2"); - } - } catch (Exception $e) { - echo $e->getMessage() . PHP_EOL; - // => Error 2 - echo $e->getPrevious()->getMessage() . PHP_EOL; - // => Error 1 + throw new Exception("Error 1"); + } finally { + throw new Exception("Error 2"); } + } catch (Exception $e) { + echo $e->getMessage() . PHP_EOL; + // => Error 2 + echo $e->getPrevious()->getMessage() . PHP_EOL; + // => Error 1 + } ]]> </programlisting> <simpara> この知識を元に、トークンの出力部を解析してみる。 </simpara> </section> - <section xml:id="_出力部の解析"> + <section xml:id="commentary--output"> <title>出力部の解析</title> <simpara> 出力部をコメントや改行を追加して再掲する: </simpara> <programlisting language="php" linenumbering="unnumbered"> <![CDATA[ - <?php - try { - f(g() / __LINE__); - } catch (Throwable $e) { - while ($e = $e->getPrevious()) { - printf('%c', $e->getLine() + 23); - } - echo "\n"; + <?php + try { + f(g() / __LINE__); + } catch (Throwable $e) { + while ($e = $e->getPrevious()) { + printf('%c', $e->getLine() + 23); } + echo "\n"; + } ]]> </programlisting> <simpara> @@ -233,7 +233,7 @@ </simpara> <programlisting language="php" linenumbering="unnumbered"> <![CDATA[ - 1, 20 => 0 / 0, + 1, 20 => 0 / 0, ]]> </programlisting> <simpara> @@ -243,33 +243,33 @@ それでは、エラーチェインを作る箇所、関数 <literal>f()</literal> を見ていく。 </simpara> </section> - <section xml:id="_データ構成部の解析"> + <section xml:id="commentary--data-construction"> <title>データ構成部の解析</title> <simpara> <literal>f()</literal> の定義を再掲する (エラーオブジェクトの行数を利用しているので、一部分だけ抜き出すと値が変わることに注意): </simpara> <programlisting language="php" linenumbering="unnumbered"> <![CDATA[ - function f(int $i) { - if ($i < 0) f(); - try { - match ($i) { - 0 => 0 / 0, // 12 行目 + function f(int $i) { + if ($i < 0) f(); + try { + match ($i) { + 0 => 0 / 0, // 12 行目 - 15, 36 => 0 / 0, - 14 => 0 / 0, - 37 => 0 / 0, + 15, 36 => 0 / 0, + 14 => 0 / 0, + 37 => 0 / 0, - // (略) + // (略) - 30 => 0 / 0, // 97 行目 - }; - } finally { - f($i - 1); - } + 30 => 0 / 0, // 97 行目 + }; + } finally { + f($i - 1); } + } ]]> </programlisting> <simpara> @@ -277,16 +277,16 @@ </simpara> <programlisting language="php" linenumbering="unnumbered"> <![CDATA[ - <?php - try { - f(g() / __LINE__); // 3 行目 + <?php + try { + f(g() / __LINE__); // 3 行目 ]]> </programlisting> <programlisting language="php" linenumbering="unnumbered"> <![CDATA[ - function g() { - return __LINE__; // 111 行目 - } + function g() { + return __LINE__; // 111 行目 + } ]]> </programlisting> <simpara> diff --git a/public/404.html b/public/404.html index 96f7478..91c2cf8 100644 --- a/public/404.html +++ b/public/404.html @@ -8,7 +8,7 @@ <meta name="description" content="リクエストされたページが見つかりません。"> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <title>Page Not Found | REPL: Rest-Eat-Program Loop</title> - <link rel="stylesheet" href="/style.css?h=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="single"> <header class="header"> diff --git a/public/about/index.html b/public/about/index.html index 1247d67..cf0b2c6 100644 --- a/public/about/index.html +++ b/public/about/index.html @@ -8,7 +8,7 @@ <meta name="description" content="このサイトの著者について"> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <title>About | REPL: Rest-Eat-Program Loop</title> - <link rel="stylesheet" href="/style.css?h=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="single"> <header class="header"> diff --git a/public/index.html b/public/index.html index cbebcb0..a748dd7 100644 --- a/public/index.html +++ b/public/index.html @@ -8,7 +8,7 @@ <meta name="description" content="nsfisis のブログサイト"> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <title>REPL: Rest-Eat-Program Loop</title> - <link rel="stylesheet" href="/style.css?h=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="single"> <header class="header"> diff --git a/public/posts/2021-03-05/my-first-post/index.html b/public/posts/2021-03-05/my-first-post/index.html index 5c8750e..c920dc0 100644 --- a/public/posts/2021-03-05/my-first-post/index.html +++ b/public/posts/2021-03-05/my-first-post/index.html @@ -8,7 +8,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> diff --git a/public/posts/2021-03-30/phperkaigi-2021/index.html b/public/posts/2021-03-30/phperkaigi-2021/index.html index f42b9b1..2e7df8c 100644 --- a/public/posts/2021-03-30/phperkaigi-2021/index.html +++ b/public/posts/2021-03-30/phperkaigi-2021/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -62,27 +62,27 @@ <section id="section--_phperkaigi_2021_参加レポ"> <h2><a href="#section--_phperkaigi_2021_参加レポ">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月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。 + 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日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。 + このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。 </p> <p> - 発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。 + 発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。 </p> <section id="section--_凡例"> <h3><a href="#section--_凡例">凡例</a></h3> <blockquote> <p> - 発表・スライドのメモ (引用ではない) + 発表・スライドのメモ (引用ではない) </p> </blockquote> <p> - 感想など + 感想など </p> </section> @@ -91,12 +91,12 @@ <section id="section--_1730_a"> <h4><a href="#section--_1730_a">17:30 [A]</a></h4> <p> - PHP で AWS Lambda + PHP で AWS Lambda </p> <blockquote> <p> - Rails のプロジェクトを PHPer のメンバのみでメンテ →他のメンバもわかる PHP にリプレースを検討 + Rails のプロジェクトを PHPer のメンバのみでメンテ →他のメンバもわかる PHP にリプレースを検討 </p> <ul> @@ -114,68 +114,68 @@ </ul> <p> - ゼロベースで作れる案件が (Railsの件とは別に) あるため、そちらで試験的に導入? + ゼロベースで作れる案件が (Railsの件とは別に) あるため、そちらで試験的に導入? </p> <p> - AWSの学習 AWS のドキュメント DevelopersIO + AWSの学習 AWS のドキュメント DevelopersIO </p> <p> - AWS Lambda のカスタムランタイムで PHP を動かす + AWS Lambda のカスタムランタイムで PHP を動かす </p> <p> - サーバのセットアップや維持管理を気にしなくて良い サーバーレスで PHP を動かすツールがすでにある サーバーレス構築はすんなり + サーバのセットアップや維持管理を気にしなくて良い サーバーレスで PHP を動かすツールがすでにある サーバーレス構築はすんなり </p> <p> - 今は Laravel がルーティングしている Laravel Livewire を Lambda に載せられないか? デプロイ方法は? バッチ処理は? (Lambda は 15分の制限) + 今は Laravel がルーティングしている Laravel Livewire を Lambda に載せられないか? デプロイ方法は? バッチ処理は? (Lambda は 15分の制限) </p> <p> - Lambda でコンテナイメージがサポートされるように + Lambda でコンテナイメージがサポートされるように </p> <p> - 抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる + 抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる </p> </blockquote> <p> - AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。 + AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。 </p> <p> - PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。 + PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。 </p> <p> - 勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。 + 勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。 </p> </section> <section id="section--_1810_a"> <h4><a href="#section--_1810_a">18:10 [A]</a></h4> <p> - 大規模サイトの SEO + 大規模サイトの SEO </p> <blockquote> <p> - 大規模サイト (100万ページ以上) Google の基準 + 大規模サイト (100万ページ以上) Google の基準 </p> <p> - クロールバジェットを意識したSEO + クロールバジェットを意識したSEO </p> <p> - 大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト (10,000以上) でコンテンツが目まぐるしく変更される これを満たさないなら、クロールバジェットを考えなくてもいい + 大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト (10,000以上) でコンテンツが目まぐるしく変更される これを満たさないなら、クロールバジェットを考えなくてもいい </p> <p> - サーチコンソール 「カバレッジ」の「除外」 多すぎるのは問題→クロールバジェットを浪費している + サーチコンソール 「カバレッジ」の「除外」 多すぎるのは問題→クロールバジェットを浪費している </p> <ul> @@ -197,28 +197,28 @@ </ul> <p> - リニューアル前のURL + リニューアル前のURL </p> <p> - インデックスは移行される リンクのURLが存在する限り、別のURLとしてクロールされる リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い リニューアルで無視されるようになったパラメータも注意 + インデックスは移行される リンクのURLが存在する限り、別のURLとしてクロールされる リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い リニューアルで無視されるようになったパラメータも注意 </p> <p> - robotes.txt で拒否しているのにクロールされる 一時的に拒否を外して 404 や 301 を読ませる 内部リンクを確認する JS でのリンクに書き換え + robotes.txt で拒否しているのにクロールされる 一時的に拒否を外して 404 や 301 を読ませる 内部リンクを確認する JS でのリンクに書き換え </p> <p> - クエリパラメータからURLのパスに <code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code> + クエリパラメータからURLのパスに <code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code> </p> <p> - URL 設計だいじ + URL 設計だいじ </p> </blockquote> <p> - SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。 + SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。 </p> </section> @@ -226,7 +226,7 @@ <h4><a href="#section--_1850_a">18:50 [A]</a></h4> <blockquote> <p> - 知覚可能 操作可能 理解可能 堅牢 ちゃんとしたHTMLを書く (閉じタグ・入れ子構造など) + 知覚可能 操作可能 理解可能 堅牢 ちゃんとしたHTMLを書く (閉じタグ・入れ子構造など) </p> <ul> @@ -252,11 +252,11 @@ </ul> <p> - button タグ →キーボード h1 タグ →スクリーンリーダー・クローラ a タグ + button タグ →キーボード h1 タグ →スクリーンリーダー・クローラ a タグ </p> <p> - WAI-ARIA HTML では表現できないセマンティクスを追加する + WAI-ARIA HTML では表現できないセマンティクスを追加する </p> <ul> @@ -293,56 +293,56 @@ </ul> <p> - まずは標準の HTML 要素で解決する 何でもかんでも WAI-ARIA を使えばいいというものではない + まずは標準の HTML 要素で解決する 何でもかんでも WAI-ARIA を使えばいいというものではない </p> <p> - マウスホバーでツールチップが出てくるが、キーボード操作では出てこない + マウスホバーでツールチップが出てくるが、キーボード操作では出てこない </p> <p> - VoiceOver + VoiceOver </p> <p> - 全ての属性を使う必要はない あくまでアクセシビリティを上げるための方法の一つにすぎない + 全ての属性を使う必要はない あくまでアクセシビリティを上げるための方法の一つにすぎない </p> </blockquote> <p> - つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。 + つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。 </p> </section> <section id="section--_1930_a"> <h4><a href="#section--_1930_a">19:30 [A]</a></h4> <p> - PHP で FUSE + PHP で FUSE </p> <p> - 個人的に楽しみだった発表。 + 個人的に楽しみだった発表。 </p> <blockquote> <p> - VFS (virtual filesystem) vs 具体的なファイルシステム + VFS (virtual filesystem) vs 具体的なファイルシステム </p> <p> - 最適な実装方法は状況により異なる + 最適な実装方法は状況により異なる </p> <p> - アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS + アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS </p> <p> - カーネルのプログラムを作るのは難しい * 権限がデカすぎる * システム全体がクラッシュ * セキュリティリスク * 開発サイクルを回しづらい * ネイティブコードにコンパイルされる言語である必要がある + カーネルのプログラムを作るのは難しい * 権限がデカすぎる * システム全体がクラッシュ * セキュリティリスク * 開発サイクルを回しづらい * ネイティブコードにコンパイルされる言語である必要がある </p> <p> - Filesystem in USEr space (FUSE) + Filesystem in USEr space (FUSE) </p> <ul> @@ -356,11 +356,11 @@ </ul> <p> - SSHFS / s3fs / Docker Desktop + SSHFS / s3fs / Docker Desktop </p> <p> - Linux 以外でも使える + Linux 以外でも使える </p> <ul> @@ -374,15 +374,15 @@ </ul> <p> - VFS: システムコールが呼ばれると、ファイルシステムによってコール FUSE: カーネル空間からユーザ空間へ通信 + VFS: システムコールが呼ばれると、ファイルシステムによってコール FUSE: カーネル空間からユーザ空間へ通信 </p> <p> - 高レベルなラッパで型をつける + 高レベルなラッパで型をつける </p> <p> - PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など) + PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など) </p> <ul> @@ -401,7 +401,7 @@ </blockquote> <p> - 期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。 この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。 + 期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。 この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。 </p> </section> </section> @@ -411,7 +411,7 @@ <section id="section--_1050_a"> <h4><a href="#section--_1050_a">10:50 [A]</a></h4> <p> - ATDD + ATDD </p> <blockquote> @@ -430,15 +430,15 @@ </ul> <p> - ユーザストーリーの受け入れ条件が曖昧になりがち デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている + ユーザストーリーの受け入れ条件が曖昧になりがち デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている </p> <p> - Q2の強化 アジャイルテストの4象限 + Q2の強化 アジャイルテストの4象限 </p> <p> - 技術面/ビジネス面 開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後) + 技術面/ビジネス面 開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後) </p> <ul> @@ -470,11 +470,11 @@ </ul> <p> - Agile Alliance ユーザストーリーのスキルレベルを高める + Agile Alliance ユーザストーリーのスキルレベルを高める </p> <p> - テストピラミッド + テストピラミッド </p> <ul> @@ -505,27 +505,27 @@ </ul> <p> - 高レベルテストが多すぎる→アイスクリームコーン アンチパターン + 高レベルテストが多すぎる→アイスクリームコーン アンチパターン </p> <p> - ATDD (Acceptance TDD) API経由・UI経由での高レベルテスト E2E test + ATDD (Acceptance TDD) API経由・UI経由での高レベルテスト E2E test </p> <p> - ストーリ受け入れテスト + ストーリ受け入れテスト </p> <p> - 入れ子のフィードバックループ ATDD(外側) と TDD(内側) + 入れ子のフィードバックループ ATDD(外側) と TDD(内側) </p> <p> - 外部品質・内部品質 + 外部品質・内部品質 </p> <p> - バーティカルスライスのデリバリー + バーティカルスライスのデリバリー </p> <ul> @@ -543,27 +543,27 @@ </ul> <p> - ユビキタス言語 手動テストもspecに書く 自動化は可能だがコスパが悪い 失敗することがわかっているテスト(レッドテスト)はCIから外す 失敗時の原因究明が難しい 饒舌なエラーメッセージ 状況のスナップショット + ユビキタス言語 手動テストもspecに書く 自動化は可能だがコスパが悪い 失敗することがわかっているテスト(レッドテスト)はCIから外す 失敗時の原因究明が難しい 饒舌なエラーメッセージ 状況のスナップショット </p> <p> - Continuous Testing + Continuous Testing </p> </blockquote> <p> - User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。 高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。 + User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。 高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。 </p> </section> <section id="section--_1150_a"> <h4><a href="#section--_1150_a">11:50 [A]</a></h4> <p> - 型解析を用いたリファクタリング + 型解析を用いたリファクタリング </p> <p> - 型のある世界で生きてきた身として大いに楽しみにしていた発表。 + 型のある世界で生きてきた身として大いに楽しみにしていた発表。 </p> <blockquote> @@ -582,151 +582,151 @@ </ul> <p> - autoload も認識できる bootstrapFiles + autoload も認識できる bootstrapFiles </p> <p> - 編集箇所と利用箇所を CI でチェック ルールレベルを徐々に引き上げていく 警告が多すぎると見落としてしまう・無視されやすくなる + 編集箇所と利用箇所を CI でチェック ルールレベルを徐々に引き上げていく 警告が多すぎると見落としてしまう・無視されやすくなる </p> <p> - 型がついていないことによるエラーが多い + 型がついていないことによるエラーが多い </p> <p> - 型よりも詳細な検査 <code>Util_Assert::min</code> + 型よりも詳細な検査 <code>Util_Assert::min</code> </p> <p> - SQL を静的解析 placeholder の型付け + SQL を静的解析 placeholder の型付け </p> <p> - 警告レベルを低いレベルから導入 タイプヒントを積極的に書いていく PHPStan の拡張を追加する + 警告レベルを低いレベルから導入 タイプヒントを積極的に書いていく PHPStan の拡張を追加する </p> </blockquote> <p> - 昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。 今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。 + 昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。 今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。 </p> </section> <section id="section--_1230_a"> <h4><a href="#section--_1230_a">12:30 [A]</a></h4> <p> - 昼食をとっていた。事前に何か食料を買っておくべきだった。 + 昼食をとっていた。事前に何か食料を買っておくべきだった。 </p> </section> <section id="section--_1310_a"> <h4><a href="#section--_1310_a">13:10 [A]</a></h4> <p> - Documentation as Code + Documentation as Code </p> <p> - この発表も以前から非常に楽しみにしていた。 + この発表も以前から非常に楽しみにしていた。 </p> <blockquote> <p> - 開発開始までのオーバーヘッド 新規にチームにジョイン 担当範囲外の機能を理解 オンボーディングのコスト + 開発開始までのオーバーヘッド 新規にチームにジョイン 担当範囲外の機能を理解 オンボーディングのコスト </p> <p> - PHPerKaigi 2020 で発表あり + PHPerKaigi 2020 で発表あり </p> <p> - 継続的にシステムの理解を助けるドキュメント + 継続的にシステムの理解を助けるドキュメント </p> <p> - 継続的ドキュメンテーション システムとドキュメントの乖離 + 継続的ドキュメンテーション システムとドキュメントの乖離 </p> <p> - 書いてあることが間違っている・足りない * 徐々にずれていく * システムの更新タイミングとドキュメントの更新タイミングに差がある + 書いてあることが間違っている・足りない * 徐々にずれていく * システムの更新タイミングとドキュメントの更新タイミングに差がある </p> <p> - システムとドキュメントは対応関係がある * 間違ったドキュメント * 存在しないドキュメント + システムとドキュメントは対応関係がある * 間違ったドキュメント * 存在しないドキュメント </p> <p> - システムとドキュメントの乖離を定量化する 継続的に システムの更新に近いタイミングで ドキュメントを更新し続ける + システムとドキュメントの乖離を定量化する 継続的に システムの更新に近いタイミングで ドキュメントを更新し続ける </p> <p> - Documentation as Code + Documentation as Code </p> <p> - コードと同じツールでドキュメントを書く * issue tracker * vcs * plain text markup * automation + コードと同じツールでドキュメントを書く * issue tracker * vcs * plain text markup * automation </p> <p> - 開発者 システム ドキュメント 構造化データ ソフトウェア + 開発者 システム ドキュメント 構造化データ ソフトウェア </p> <p> - システムから構造化データを抽出する PHPDoc OpenAPI + システムから構造化データを抽出する PHPDoc OpenAPI </p> <p> - ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する + ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する </p> <p> - ビューの単位でドキュメントに + ビューの単位でドキュメントに </p> <p> - スタックトレースからのドキュメント生成 + スタックトレースからのドキュメント生成 </p> </blockquote> <p> - ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。 + ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。 </p> </section> <section id="section--_1410_a"> <h4><a href="#section--_1410_a">14:10 [A]</a></h4> <p> - cookie による session 管理 + cookie による session 管理 </p> <p> - 全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。 + 全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。 </p> </section> <section id="section--_1450_a"> <h4><a href="#section--_1450_a">14:50 [A]</a></h4> <p> - PHP のエラーと例外 + PHP のエラーと例外 </p> <blockquote> <p> - エラー PHPエンジンがエラーを通知する 例外 プログラムが投げる + エラー PHPエンジンがエラーを通知する 例外 プログラムが投げる </p> <p> - PHP7-8とエラー + PHP7-8とエラー </p> <p> - PHPエンジンのエラーの一部が に変換されるようになった → try-catch で捕捉できる + PHPエンジンのエラーの一部が に変換されるようになった → try-catch で捕捉できる </p> <p> - は例外とは異なる + は例外とは異なる </p> <p> - PHP8 でエラーレベルの引き上げ + PHP8 でエラーレベルの引き上げ </p> <ul> @@ -754,19 +754,19 @@ </ul> <p> - 例外 * 捕捉して事後処理 * 捕捉せず(or 捕捉した上で)さらに上に是非を問う + 例外 * 捕捉して事後処理 * 捕捉せず(or 捕捉した上で)さらに上に是非を問う </p> <p> - 開発段階で例外を把握し、ハンドリングを考えておく + 開発段階で例外を把握し、ハンドリングを考えておく </p> <p> - と + と </p> <p> - はキャッチすべきでない + はキャッチすべきでない </p> <ul> @@ -805,152 +805,152 @@ </ul> <p> - 捕捉して対応するのではなく、未然に防ぐ + 捕捉して対応するのではなく、未然に防ぐ </p> <p> - 独自例外を使う を投げてしまうと、 catch ()せざるを得ない →catch 範囲が広すぎる + 独自例外を使う を投げてしまうと、 catch ()せざるを得ない →catch 範囲が広すぎる </p> <p> - SPL の例外を使う + SPL の例外を使う </p> <p> - 例外翻訳 上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する 下位レイヤの知識に依存させない + 例外翻訳 上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する 下位レイヤの知識に依存させない </p> <p> - @throws 捕捉してほしい例外を書き連ねておく + @throws 捕捉してほしい例外を書き連ねておく </p> <p> - 呼び出しもとに負わせたい責任 + 呼び出しもとに負わせたい責任 </p> </blockquote> <p> - PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。 + PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。 </p> <p> - 個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。 + 個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。 </p> <p> - PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。 + PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。 </p> </section> <section id="section--_1530_a"> <h4><a href="#section--_1530_a">15:30 [A]</a></h4> <p> - Laravel のメール認証 + Laravel のメール認証 </p> <p> - Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。 + Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。 </p> </section> <section id="section--_1610_a"> <h4><a href="#section--_1610_a">16:10 [A]</a></h4> <p> - gRPC + gRPC </p> <blockquote> <p> - Unary RPCs Server streaming RPCs Client streaming RPCs Bidirectional streaming RPCs + Unary RPCs Server streaming RPCs Client streaming RPCs Bidirectional streaming RPCs </p> <p> - Protobuf + Protobuf </p> <p> - 実装とAPIが乖離しにくい 自動生成 複数言語でも相互に使える + 実装とAPIが乖離しにくい 自動生成 複数言語でも相互に使える </p> <p> - マイクロサービスのサービス通信 スマホアプリ ゲームサーバ + マイクロサービスのサービス通信 スマホアプリ ゲームサーバ </p> <p> - PHP では? + PHP では? </p> <p> - PHP ではストリーミングが難しい リクエストごとにプロセスが使い捨て + PHP ではストリーミングが難しい リクエストごとにプロセスが使い捨て </p> <p> - PHP ではgRPCのクライアントしか対応していない + PHP ではgRPCのクライアントしか対応していない </p> <p> - gRPC-Web ブラウザで扱うためのJSライブラリ+プロトコル + gRPC-Web ブラウザで扱うためのJSライブラリ+プロトコル </p> <p> - HTTP/1.1 でも使える Unary RPC と Server streaming RPC のみ + HTTP/1.1 でも使える Unary RPC と Server streaming RPC のみ </p> <p> - Envoy Nginx などで相互に gRPC と gRPC-Web で変換 + Envoy Nginx などで相互に gRPC と gRPC-Web で変換 </p> <p> - Amp イベント駆動な並行処理のフレームワーク + Amp イベント駆動な並行処理のフレームワーク </p> <p> - HTTP/2 対応 + HTTP/2 対応 </p> <p> - C#のgRPC-Webが楽 + C#のgRPC-Webが楽 </p> </blockquote> <p> - (発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。 + (発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。 </p> </section> <section id="section--_1650_a"> <h4><a href="#section--_1650_a">16:50 [A]</a></h4> <p> - アーキテクチャテスト + アーキテクチャテスト </p> <blockquote> <p> - Independent Core Layer Pattern + Independent Core Layer Pattern </p> <p> - 開発初期のアーキテクチャが崩れる アーキテクチャ観点のコードレビューができない + 開発初期のアーキテクチャが崩れる アーキテクチャ観点のコードレビューができない </p> <p> - どこにクラスを置けばよいか? ドキュメントがない + どこにクラスを置けばよいか? ドキュメントがない </p> <p> - アーキテクチャ設計に関する知識が属人化・暗黙知化 + アーキテクチャ設計に関する知識が属人化・暗黙知化 </p> <p> - ガイドライン * 最初にルールを決めるのは簡単 * ルール通り作り始めるのも簡単 * →維持するのが難しい、人が決めたものゆえ壊れやすい + ガイドライン * 最初にルールを決めるのは簡単 * ルール通り作り始めるのも簡単 * →維持するのが難しい、人が決めたものゆえ壊れやすい </p> <p> - PHP の特性 * クラスは public * 可視性の制御が public / protected / private のみ * 依存関係の制御が困難 + PHP の特性 * クラスは public * 可視性の制御が public / protected / private のみ * 依存関係の制御が困難 </p> <p> - アーキテクチャテスト クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する + アーキテクチャテスト クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する </p> <ul> @@ -964,15 +964,15 @@ </ul> <p> - Independent Core Layer Pattern + Independent Core Layer Pattern </p> <p> - アーキテクチャテストの失敗 * 実装誤り * or アーキテクチャが適切でない * 開発の過程でフィードバックしていく + アーキテクチャテストの失敗 * 実装誤り * or アーキテクチャが適切でない * 開発の過程でフィードバックしていく </p> <p> - モジュラーモノリス→マイクロサービスへ + モジュラーモノリス→マイクロサービスへ </p> </blockquote> </section> @@ -981,30 +981,30 @@ <section id="section--_day_2_20210328"> <h3><a href="#section--_day_2_20210328">Day 2 (2021/03/28)</a></h3> <p> - 冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。 + 冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。 </p> <p> - 残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。 + 残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。 </p> </section> <section id="section--_全体の感想"> <h3><a href="#section--_全体の感想">全体の感想</a></h3> <p> - Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。 + Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。 </p> <p> - 今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。 + 今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。 </p> <p> - 1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 まあ初カンファレンスだし、とお茶を濁しておこう。 + 1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 まあ初カンファレンスだし、とお茶を濁しておこう。 </p> <p> - さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。 + さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。 </p> <p> @@ -1013,11 +1013,11 @@ </p> <p> - 最後になりましたが、毎年の PHPerKaigi 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました! (ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い) + 最後になりましたが、毎年の PHPerKaigi 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました! (ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い) </p> <p> - ではまた来年。 + ではまた来年。 </p> </section> </section> diff --git a/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html b/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html index dc9d084..76806ba 100644 --- a/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html +++ b/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -57,7 +57,7 @@ </ol> </section> <p> - この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</a> + この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</a> </p> <p> @@ -66,7 +66,7 @@ </p> <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"><iostream></span></span> @@ -86,25 +86,25 @@ [[<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 << <span class="hljs-string">"Hello, World!"</span> << std::endl; + std::cout << <span class="hljs-string">"Hello, World!"</span> << 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 + コンパイラのバージョン $ 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 + コンパイルコマンド (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> を読んでいた時、次の文が目に止まった。 + 別件で cppreference.com の <a href="https://en.cppreference.com/w/cpp/language/identifiers">identifier のページ</a> を読んでいた時、次の文が目に止まった。 </p> <blockquote> @@ -121,40 +121,40 @@ std::cout << <span class="hljs-string">"Hello, World!"</span> &l </blockquote> <p> - キーワードでも属性として指定する場合は非キーワードとして使えるらしい。 実際にやってみる。 + キーワードでも属性として指定する場合は非キーワードとして使えるらしい。 実際にやってみる。 </p> <p> - 同サイトの <a href="https://en.cppreference.com/w/cpp/keyword">keywords のページ</a> から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。 大量の警告 (unknown attribute `〇〇' ignored) がコンパイラから出力されるが、コンパイルできる。 + 同サイトの <a href="https://en.cppreference.com/w/cpp/keyword">keywords のページ</a> から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。 大量の警告 (unknown attribute `〇〇' ignored) がコンパイラから出力されるが、コンパイルできる。 </p> <p> - 上のコードでは <code>[[using]]</code> をコメントアウトしているが、これは <code>using</code> キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。 + 上のコードでは <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 の仕様も見てみる (正確には標準化前のドラフト)。 + 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> + 引用元: <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. + 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> とみなされる」とある。どうやら間違いないようだ。 + 「<code>identifier</code> の構文上の要件を満たすキーワードまたは代替トークンが <code>attribute-token</code> に含まれている場合、<code>identifier</code> とみなされる」とある。どうやら間違いないようだ。 </p> <p> - ところで、代替トークン (alternative token) とは <code>and</code> (<code>&</code>) や <code>bitor</code> (<code>|</code>) などのことだが、<code>identifier</code> の構文上の要件を満たさないような代替トークンなどあるのか? 疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい (参考: <a href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</a>) + ところで、代替トークン (alternative token) とは <code>and</code> (<code>&</code>) や <code>bitor</code> (<code>|</code>) などのことだが、<code>identifier</code> の構文上の要件を満たさないような代替トークンなどあるのか? 疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい (参考: <a href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</a>) </p> <ul> @@ -184,11 +184,11 @@ std::cout << <span class="hljs-string">"Hello, World!"</span> &l </ul> <p> - 「<code>identifier</code> の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。 + 「<code>identifier</code> の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。 </p> <p> - 調べた感想: 字句解析器か構文解析器が辛そう + 調べた感想: 字句解析器か構文解析器が辛そう </p> </div> </article> diff --git a/public/posts/2021-10-02/python-unbound-local-error/index.html b/public/posts/2021-10-02/python-unbound-local-error/index.html index 5d06a25..fe3b020 100644 --- a/public/posts/2021-10-02/python-unbound-local-error/index.html +++ b/public/posts/2021-10-02/python-unbound-local-error/index.html @@ -9,7 +9,7 @@ <meta name="keywords" content="Python,Python 3"> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <title>【Python】 クロージャとUnboundLocalError: local variable 'x' referenced before assignment | REPL: Rest-Eat-Program Loop</title> - <link rel="stylesheet" href="/style.css?h=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -57,7 +57,7 @@ </ol> </section> <p> - この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</a> + この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</a> </p> <p> @@ -66,11 +66,11 @@ </p> <p> - 本記事は Python 3.7.6 の動作結果を元にして書かれている。 + 本記事は Python 3.7.6 の動作結果を元にして書かれている。 </p> <p> - Python でクロージャを作ろうと、次のようなコードを書いた。 + 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>(): @@ -82,17 +82,17 @@ g() f()</code></pre> <p> - 関数 <code>g</code> から 関数 <code>f</code> のスコープ内で定義された変数 <code>x</code> を参照し、それに 1 を足そうとしている。 これを実行すると <code>x += 1</code> の箇所でエラーが発生する。 + 関数 <code>g</code> から 関数 <code>f</code> のスコープ内で定義された変数 <code>x</code> を参照し、それに 1 を足そうとしている。 これを実行すると <code>x += 1</code> の箇所でエラーが発生する。 </p> <blockquote> <p> - UnboundLocalError: local variable `x' referenced before assignment + UnboundLocalError: local variable `x' referenced before assignment </p> </blockquote> <p> - local変数 <code>x</code> が代入前に参照された、とある。これは、<code>f</code> の <code>x</code> を参照するのではなく、新しく別の変数を <code>g</code> 内に作ってしまっているため。 前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<code>var</code> を変数宣言のための構文として擬似的に利用している。 + 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> @@ -107,7 +107,7 @@ x += <span class="hljs-number">1</span> <span class="hljs-comment"># x に 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>(): @@ -118,7 +118,7 @@ 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> を探しに行くようになる。 + <code>(*)</code> のように、<code>nonlocal</code> を追加する。これにより一つ外側のスコープ (<code>g</code> の一つ外側 = <code>f</code>) で定義されている <code>x</code> を探しに行くようになる。 </p> </div> </article> diff --git a/public/posts/2021-10-02/ruby-detect-running-implementation/index.html b/public/posts/2021-10-02/ruby-detect-running-implementation/index.html index 59bf445..3557c4a 100644 --- a/public/posts/2021-10-02/ruby-detect-running-implementation/index.html +++ b/public/posts/2021-10-02/ruby-detect-running-implementation/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -54,7 +54,7 @@ </ol> </section> <p> - この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791">https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791</a> + この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791">https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791</a> </p> <p> @@ -63,19 +63,19 @@ </p> <p> - Ruby という言語には複数の実装があるが、それらをスクリプト上からどのようにして programmatically に見分ければよいだろうか。 + Ruby という言語には複数の実装があるが、それらをスクリプト上からどのようにして programmatically に見分ければよいだろうか。 </p> <p> - <code>Object</code> クラスに定義されている <code>RUBY_ENGINE</code> という定数がこの用途に使える。 + <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> + 参考: <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 'p RUBY_ENGINE' @@ -86,11 +86,11 @@ jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] "jruby"</code></pre> <p> - それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。 + それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。 </p> <p> - <a href="https://stackoverflow.com/a/9894232">What values for RUBY_ENGINE correspond to which Ruby implementations?</a> より引用: + <a href="https://stackoverflow.com/a/9894232">What values for RUBY_ENGINE correspond to which Ruby implementations?</a> より引用: </p> <blockquote> @@ -192,15 +192,15 @@ jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] </blockquote> <p> - なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も <code>'ruby'</code> が返ってくることを確認済み。 + なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も <code>'ruby'</code> が返ってくることを確認済み。 </p> <p> - この表にない主要な処理系として、https://mruby.org[mruby] は <code>'mruby'</code> を返す。 + この表にない主要な処理系として、https://mruby.org[mruby] は <code>'mruby'</code> を返す。 </p> <p> - <a href="https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35">mruby 該当部分のソース</a> より引用: + <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">/* diff --git a/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html b/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html index 31107fc..097d417 100644 --- a/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html +++ b/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -57,7 +57,7 @@ </ol> </section> <p> - この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/787a8cf888a304497223">https://qiita.com/nsfisis/items/787a8cf888a304497223</a> + この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/787a8cf888a304497223">https://qiita.com/nsfisis/items/787a8cf888a304497223</a> </p> <p> @@ -68,58 +68,58 @@ <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> が使える (場合によっては使う必要がある)。 + <code>case</code> - <code>in</code> によるパターンマッチング構文でも、<code>case</code> - <code>when</code> と同じように <code>then</code> が使える (場合によっては使う必要がある)。 </p> </section> <section id="section--_then_とは"> <h2><a href="#section--_then_とは"><code>then</code> とは</a></h2> <p> - 使われることは稀だが、Ruby では <code>then</code> がキーワードになっている。次のように使う: + 使われることは稀だが、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">"Y"</span> - <span class="hljs-keyword">else</span> +<span class="hljs-keyword">else</span> puts <span class="hljs-string">"N"</span> - <span class="hljs-keyword">end</span></code></pre> +<span class="hljs-keyword">end</span></code></pre> <p> - このキーワードが現れうる場所はいくつかあり、<code>if</code>、<code>unless</code>、<code>rescue</code>、<code>case</code> 構文がそれに当たる。 上記のように、何か条件を書いた後 <code>then</code> を置き、式がそこで終了していることを示すマーカーとして機能する。 + このキーワードが現れうる場所はいくつかあり、<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 + a <span class="hljs-keyword">end</span> <span class="hljs-keyword">unless</span> x <span class="hljs-keyword">then</span> -a + a <span class="hljs-keyword">end</span> <span class="hljs-keyword">begin</span> -a + a <span class="hljs-keyword">rescue</span> <span class="hljs-keyword">then</span> -b + 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 + a <span class="hljs-keyword">end</span></code></pre> </section> <section id="section--_なぜ普段は書かなくてもよいのか"> <h2><a href="#section--_なぜ普段は書かなくてもよいのか">なぜ普段は書かなくてもよいのか</a></h2> <p> - 普通 Ruby のコードで <code>then</code> を書くことはない。なぜか。次のコードを実行してみるとわかる。 + 普通 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">'Hello, World!'</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' or ';' or '\n' @@ -129,31 +129,31 @@ if true puts 'Hello, World!' end ...f true puts 'Hello, World!' end</code></pre> <p> - 二つ目のメッセージは無視して一つ目を読むと、<code>then</code> か <code>;</code> か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。 + 二つ目のメッセージは無視して一つ目を読むと、<code>then</code> か <code>;</code> か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。 </p> <p> - ポイントは改行が <code>then</code> (や <code>;</code>) の代わりとなることである。<code>true</code> の後に改行を入れてみる。 + ポイントは改行が <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">'Hello, World!'</span> <span class="hljs-keyword">end</span></code></pre> <p> - 無事 Hello, World! と出力されるようになった。 + 無事 Hello, World! と出力されるようになった。 </p> </section> <section id="section--_なぜ_then_や_や改行が必要か"> <h2><a href="#section--_なぜ_then_や_や改行が必要か">なぜ <code>then</code> や <code>;</code> や改行が必要か</a></h2> <p> - なぜ <code>then</code> や <code>;</code> や改行 (以下 「<code>then</code> 等」) が必要なのだろうか。次の例を見てほしい: + なぜ <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> も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。 この例は二通りに解釈できる。 + <code>then</code> も <code>;</code> も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。 この例は二通りに解釈できる。 </p> <pre class="highlight" language="ruby" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価</span> @@ -167,18 +167,18 @@ b <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> も同じ役割を持つ。 + <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> は必要ない。 + Ruby の場合、プログラマーが書きやすいよう改行でもって <code>then</code> が代用できるので、ほとんどの場合 <code>then</code> は必要ない。 </p> </section> <section id="section--_case_in_における_then"> <h2><a href="#section--_case_in_における_then"><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 の説明は省略)。 + ようやく本題にたどり着いた。来る Ruby 3.0 では <code>case</code> と <code>in</code> キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして <code>then</code> 等が必要になる。 (現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。 </p> <p> @@ -186,45 +186,45 @@ b </p> <pre class="highlight" language="yacc" linenumbering="unnumbered"><code>p_case_body : keyword_in - { +{ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL); p->command_start = FALSE; $<ctxt>1 = p->ctxt; p->ctxt.in_kwarg = 1; $<tbl>$ = push_pvtbl(p); - } - { +} +{ $<tbl>$ = push_pktbl(p); - } - p_top_expr then - { +} +p_top_expr then +{ pop_pktbl(p, $<tbl>3); pop_pvtbl(p, $<tbl>2); p->ctxt.in_kwarg = $<ctxt>1.in_kwarg; - } - compstmt - p_cases - { +} +compstmt +p_cases +{ /*%%%*/ $$ = NEW_IN($4, $7, $8, &@$); /*% %*/ /*% ripper: in!($4, $7, escape_Qundef($8)) %*/ - } - ;</code></pre> +} +;</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>、改行のいずれかである。 + ここで、<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通りのいずれかになる: + これにより、<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 @@ -235,11 +235,11 @@ b <span class="hljs-keyword">case</span> x <span class="hljs-keyword">in</span> <span class="hljs-number">1</span> -a + a <span class="hljs-keyword">in</span> <span class="hljs-number">2</span> -b + b <span class="hljs-keyword">in</span> <span class="hljs-number">3</span> -c + c <span class="hljs-keyword">end</span> <span class="hljs-keyword">case</span> x @@ -249,7 +249,7 @@ 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> と似たような見た目になる。 + ところで、<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 diff --git a/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html b/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html index 5bb46a0..9e77a85 100644 --- a/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html +++ b/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -54,7 +54,7 @@ </ol> </section> <p> - この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</a> + この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</a> </p> <p> @@ -65,7 +65,7 @@ <section id="section--_前置き"> <h2><a href="#section--_前置き">前置き</a></h2> <p> - Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。 + Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。 </p> <pre class="highlight" language="rust" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta">#![allow(non_camel_case_types)]</span> @@ -90,12 +90,12 @@ <span class="hljs-keyword">struct</span> <span class="hljs-title class_">str</span>;</code></pre> <p> - では、普段単に <code>bool</code> と書いたとき、この <code>bool</code> は一体どこから来ているのか。rustc のソースを追ってみた。 + では、普段単に <code>bool</code> と書いたとき、この <code>bool</code> は一体どこから来ているのか。rustc のソースを追ってみた。 </p> <blockquote> <p> - 前提知識: 一般的なコンパイラの構造、用語。<code>rustc</code> そのものの知識は不要 (というよりも筆者自身がよく知らない) + 前提知識: 一般的なコンパイラの構造、用語。<code>rustc</code> そのものの知識は不要 (というよりも筆者自身がよく知らない) </p> </blockquote> </section> @@ -103,7 +103,7 @@ <section id="section--_調査"> <h2><a href="#section--_調査">調査</a></h2> <p> - 調査に使用したソース (調査時点での最新 master) + 調査に使用したソース (調査時点での最新 master) </p> <p> @@ -111,15 +111,15 @@ </p> <p> - どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。 + どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。 </p> <p> - 大雑把な構造としては、<code>compiler</code> フォルダ以下に <code>rustc_*</code> という名前のクレートが数十個入っている。これがどうやら <code>rustc</code> コマンドの実装部のようだ。 + 大雑把な構造としては、<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> してみる。 + <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 "\bi128\b" | wc # i128 @@ -132,7 +132,7 @@ $ git grep "\bbool\b" | wc # cf. bool の結果 3563 23577 294659</code></pre> <p> - 165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。 + 165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。 </p> <pre class="highlight monospaced"><code>$ git grep "\bi128\b" @@ -141,7 +141,7 @@ rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128)); ...</code></pre> <p> - <code>rustc_resolve</code> というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。 + <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> @@ -149,84 +149,84 @@ rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128)); <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<Symbol, PrimTy>, + primitive_types: FxHashMap<Symbol, PrimTy>, } <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">-></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>(); + <span class="hljs-keyword">fn</span> <span class="hljs-title function_">new</span>() <span class="hljs-punctuation">-></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 } -} + 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 にも、 + これは初めに列挙したプリミティブ型の一覧と一致している。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. + 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 の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。 + とある。次はこの 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> + <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>( -&<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-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">-></span> <span class="hljs-type">Option</span><LexicalScopeBinding<<span class="hljs-symbol">'a</span>>> { -<span class="hljs-comment">// (略)</span> + <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>(&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-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>(&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> + <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> など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。 + 関数名や 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> は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。 + なお、<code>ns</code> は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この <code>if</code> は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。 </p> <p> - 重要なのは、これが <code>resolve_ident_in_lexical_scope()</code> の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。 + 重要なのは、これが <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> @@ -234,18 +234,18 @@ ns: Namespace, <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>; + <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> という名前の別の型が見つかるからだ。 + ここで <code>main()</code> の <code>bool</code> は <code>struct bool</code> として解決される。なぜなら、プリミティブ型の判定をする前に <code>bool</code> という名前の別の型が見つかるからだ。 </p> </section> <section id="section--_まとめ"> <h2><a href="#section--_まとめ">まとめ</a></h2> <p> - Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。 + Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。 </p> </section> </div> diff --git a/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html b/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html index 3c6342b..44ee689 100644 --- a/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html +++ b/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -54,7 +54,7 @@ </ol> </section> <p> - この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/79ab4db8564032de0b25">https://qiita.com/nsfisis/items/79ab4db8564032de0b25</a> + この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/79ab4db8564032de0b25">https://qiita.com/nsfisis/items/79ab4db8564032de0b25</a> </p> <p> @@ -65,14 +65,14 @@ <section id="section--_tl_dr"> <h2><a href="#section--_tl_dr">TL; DR</a></h2> <p> - 違いはない。ただのエイリアス。 + 違いはない。ただのエイリアス。 </p> </section> <section id="section--_調査記録"> <h2><a href="#section--_調査記録">調査記録</a></h2> <p> - Vim の autocmd events には似通った名前のものがいくつかある。大抵は <code>:help</code> に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。 + Vim の autocmd events には似通った名前のものがいくつかある。大抵は <code>:help</code> に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。 </p> <ul> @@ -90,43 +90,43 @@ </ul> <p> - このうち、<code>BufAdd</code>/<code>BufCreate</code> に関しては、<code>:help BufCreate</code> に + このうち、<code>BufAdd</code>/<code>BufCreate</code> に関しては、<code>:help BufCreate</code> に </p> <blockquote> <p> - The BufCreate event is for historic reasons. + The BufCreate event is for historic reasons. </p> </blockquote> <p> - とあり、おそらくは <code>BufAdd</code> のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため vim と neovim のソースコードを調査した。 + とあり、おそらくは <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> + ソースコードへのリンク <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--_vim_のソースコード"> <h3><a href="#section--_vim_のソースコード">vim のソースコード</a></h3> <p> - 以下は、autocmd events の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。 + 以下は、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">"BufAdd"</span>, EVENT_BUFADD}, + <pre class="highlight" language="c" linenumbering="unnumbered"><code class="highlight">{<span class="hljs-string">"BufAdd"</span>, EVENT_BUFADD}, {<span class="hljs-string">"BufCreate"</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">"BufRead"</span>, EVENT_BUFREADPOST}, + <pre class="highlight" language="c" linenumbering="unnumbered"><code class="highlight">{<span class="hljs-string">"BufRead"</span>, EVENT_BUFREADPOST}, {<span class="hljs-string">"BufReadCmd"</span>, EVENT_BUFREADCMD}, {<span class="hljs-string">"BufReadPost"</span>, EVENT_BUFREADPOST},</code></pre> @@ -134,7 +134,7 @@ <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">"BufWrite"</span>, EVENT_BUFWRITEPRE}, + <pre class="highlight" language="c" linenumbering="unnumbered"><code class="highlight">{<span class="hljs-string">"BufWrite"</span>, EVENT_BUFWRITEPRE}, {<span class="hljs-string">"BufWritePost"</span>, EVENT_BUFWRITEPOST}, {<span class="hljs-string">"BufWritePre"</span>, EVENT_BUFWRITEPRE},</code></pre> </section> @@ -142,14 +142,14 @@ <section id="section--_neovim_のソースコード"> <h3><a href="#section--_neovim_のソースコード">neovim のソースコード</a></h3> <p> - neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua で書かれている。以下にある通り、はっきり <code>aliases</code> と書かれている。 + 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 = { + <pre class="highlight" language="lua" linenumbering="unnumbered"><code class="highlight">aliases = { BufCreate = <span class="hljs-string">'BufAdd'</span>, BufRead = <span class="hljs-string">'BufReadPost'</span>, BufWrite = <span class="hljs-string">'BufWritePre'</span>, @@ -157,18 +157,18 @@ FileEncoding = <span class="hljs-string">'EncodingChanged'</span>, },</code></pre> <p> - ところで、上では取り上げなかった <code>FileEncoding</code> だが、これは <code>:help FileEncoding</code> にしっかりと書いてある。 + ところで、上では取り上げなかった <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> + FileEncoding Obsolete. It still works and is equivalent + to |EncodingChanged|.</code></pre> </section> <section id="section--_まとめ"> <h3><a href="#section--_まとめ">まとめ</a></h3> <p> - 記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。 + 記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。 </p> <ul> @@ -210,7 +210,7 @@ to |EncodingChanged|.</code></pre> </ul> <p> - ところでこの調査で知ったのだが、<code>BufRead</code> と <code>BufWrite</code> は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら <code>Pre</code>/<code>Post</code> 付きのものを使った方が分かりやすいだろう。 + ところでこの調査で知ったのだが、<code>BufRead</code> と <code>BufWrite</code> は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら <code>Pre</code>/<code>Post</code> 付きのものを使った方が分かりやすいだろう。 </p> </section> </section> diff --git a/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html b/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html index 48b57ac..6b9e423 100644 --- a/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html +++ b/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -54,7 +54,7 @@ </ol> </section> <p> - この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/4fefb361d9a693803520">https://qiita.com/nsfisis/items/4fefb361d9a693803520</a> + この記事は Qiita から移植してきたものです。 元 URL: <a href="https://qiita.com/nsfisis/items/4fefb361d9a693803520">https://qiita.com/nsfisis/items/4fefb361d9a693803520</a> </p> <p> @@ -65,12 +65,12 @@ <section id="section--_バージョン情報"> <h2><a href="#section--_バージョン情報">バージョン情報</a></h2> <p> - <code>:version</code> の一部 + <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. + 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> @@ -80,60 +80,60 @@ <section id="section--_tac_tail"> <h3><a href="#section--_tac_tail"><code>tac</code> / <code>tail</code></a></h3> <p> - <code>tac</code> や <code>tail -r</code> などの外部コマンドを <code>!</code> を使って呼び出し、置き換える。 + <code>tac</code> や <code>tail -r</code> などの外部コマンドを <code>!</code> を使って呼び出し、置き換える。 </p> <blockquote> <p> - :h v_! + :h v_! </p> </blockquote> <p> - <code>tac</code> コマンドや <code>tail</code> の <code>-r</code> オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい + <code>tac</code> コマンドや <code>tail</code> の <code>-r</code> オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい </p> </section> <section id="section--_gm0"> <h3><a href="#section--_gm0"><code>:g/^/m0</code></a></h3> <p> - こちらは外部コマンドに頼らず、Vim の機能のみを使う。<code>g</code> は <code>:global</code> コマンドの、<code>m</code> は <code>:move</code> コマンドの略 + こちらは外部コマンドに頼らず、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 コマンドを呼び出す。 + <code>:global</code> コマンドは <code>:[range]global/{pattern}/[command]</code> のように使い、<code>[range]</code> で指定された範囲の行のうち、<code>{pattern}</code> で指定された検索パターンにマッチする行に対して、順番に <code>[command]</code> で指定された Ex コマンドを呼び出す。 </p> <blockquote> <p> - :h :global + :h :global </p> </blockquote> <p> - <code>:move</code> コマンドは <code>[range]:move {address}</code> のように使い、<code>[range]</code> で指定された範囲の行を <code>{address}</code> で指定された位置に移動させる。 + <code>:move</code> コマンドは <code>[range]:move {address}</code> のように使い、<code>[range]</code> で指定された範囲の行を <code>{address}</code> で指定された位置に移動させる。 </p> <blockquote> <p> - :h :move + :h :move </p> </blockquote> <p> - <code>:g/^/m0</code> のように組み合わせると、「すべての行を1行ずつ 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。 + <code>:g/^/m0</code> のように組み合わせると、「すべての行を1行ずつ 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。 </p> <p> - なお、<code>:g/^/m0</code> は全ての行を入れ替えるが、<code>:N,Mg/^/mN-1</code> とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。 + なお、<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"><line1></span>,<span class="hljs-symbol"><line2></span>g/^/<span class="hljs-keyword">m</span><span class="hljs-symbol"><line1></span>-<span class="hljs-number">1</span></code></pre> + \ Reverse + \ <span class="hljs-symbol"><line1></span>,<span class="hljs-symbol"><line2></span>g/^/<span class="hljs-keyword">m</span><span class="hljs-symbol"><line1></span>-<span class="hljs-number">1</span></code></pre> <p> - これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。 + これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。 </p> </section> </section> @@ -141,12 +141,12 @@ <section id="section--_gm0_の問題点"> <h2><a href="#section--_gm0_の問題点"><code>:g/^/m0</code> の問題点</a></h2> <p> - <code>:global</code> コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。<code>^</code> は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。<code>'hlsearch'</code> オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと <code>n</code> コマンドなどの際に不便である。 + <code>:global</code> コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。<code>^</code> は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。<code>'hlsearch'</code> オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと <code>n</code> コマンドなどの際に不便である。 </p> <blockquote> <p> - :h @/ + :h @/ </p> </blockquote> </section> @@ -155,60 +155,60 @@ <h2><a href="#section--_解決策">解決策</a></h2> <blockquote> <p> - [2020/9/28追記] より簡潔な方法を見つけたので次節に追記した + [2020/9/28追記] より簡潔な方法を見つけたので次節に追記した </p> </blockquote> <p> - 前述した <code>:Reverse</code> コマンドの定義を少し変えて、次のようにする: + 前述した <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">"%d,%dg/^/m%d"</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> + <span class="hljs-keyword">execute</span> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%d,%dg/^/m%d"</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"><SID></span>reverse_lines(<span class="hljs-symbol"><line1></span>, <span class="hljs-symbol"><line2></span>)</code></pre> +command! -bar -<span class="hljs-built_in">range</span>=% + \ Reverse + \ <span class="hljs-keyword">call</span> <span class="hljs-symbol"><SID></span>reverse_lines(<span class="hljs-symbol"><line1></span>, <span class="hljs-symbol"><line2></span>)</code></pre> <p> - 実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。 + 実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。 </p> <p> - この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが <code>^</code> で上書きされることがなくなる。 + この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが <code>^</code> で上書きされることがなくなる。 </p> <p> - Vim のヘルプから該当箇所を引用する (強調は筆者による)。 + Vim のヘルプから該当箇所を引用する (強調は筆者による)。 </p> <blockquote> <p> - :h autocmd-searchpat + :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' option. + <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' option. </p> </blockquote> <p> - これは autocommand の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは <code>:nohlsearch</code> のヘルプにある。同じく該当箇所を引用する (強調は筆者による)。 + これは autocommand の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは <code>:nohlsearch</code> のヘルプにある。同じく該当箇所を引用する (強調は筆者による)。 </p> <blockquote> <p> - :h :nohlsearch + :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> + (略) 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> の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。 + この仕様により、<code>:g/^/m0</code> の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。 </p> </section> @@ -216,21 +216,21 @@ <h2><a href="#section--_解決策_改訂版">解決策 (改訂版)</a></h2> <blockquote> <p> - [2020/9/28追記] より簡潔な方法を見つけたため追記する + [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"><line1></span>,<span class="hljs-symbol"><line2></span>g/^/<span class="hljs-keyword">m</span><span class="hljs-symbol"><line1></span>-<span class="hljs-number">1</span></code></pre> + \ Reverse + \ keeppatterns <span class="hljs-symbol"><line1></span>,<span class="hljs-symbol"><line2></span>g/^/<span class="hljs-keyword">m</span><span class="hljs-symbol"><line1></span>-<span class="hljs-number">1</span></code></pre> <p> - まさにこのための Exコマンド、<code>:keeppatterns</code> が存在する。<code>:keeppatterns {command}</code> のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。 + まさにこのための Exコマンド、<code>:keeppatterns</code> が存在する。<code>:keeppatterns {command}</code> のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。 </p> <blockquote> <p> - :h :keeppatterns + :h :keeppatterns </p> </blockquote> </section> @@ -239,9 +239,9 @@ <h2><a href="#section--_コピペ用再掲">コピペ用再掲</a></h2> <pre class="highlight" language="vim" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment">" License: Public Domain</span> - command! -bar -<span class="hljs-built_in">range</span>=% - \ Reverse - \ keeppatterns <span class="hljs-symbol"><line1></span>,<span class="hljs-symbol"><line2></span>g/^/<span class="hljs-keyword">m</span><span class="hljs-symbol"><line1></span>-<span class="hljs-number">1</span></code></pre> +command! -bar -<span class="hljs-built_in">range</span>=% + \ Reverse + \ keeppatterns <span class="hljs-symbol"><line1></span>,<span class="hljs-symbol"><line2></span>g/^/<span class="hljs-keyword">m</span><span class="hljs-symbol"><line1></span>-<span class="hljs-number">1</span></code></pre> </section> </div> </article> diff --git a/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html b/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html index 86679f3..d834bb8 100644 --- a/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html +++ b/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -62,69 +62,69 @@ </li> </ol> </section> - <section id="section--_はじめに"> - <h2><a href="#section--_はじめに">はじめに</a></h2> + <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問作成した。この記事では、これらの問題の解説をおこなう。 + 本日開始された <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> + リポジトリはこちら: <a href="https://github.com/nsfisis/PHPerKaigi2022-tokens">https://github.com/nsfisis/PHPerKaigi2022-tokens</a> </p> </section> <section id="section--_第1問_brainf_ck_php"> <h2><a href="#section--_第1問_brainf_ck_php">第1問 brainf_ck.php</a></h2> <p> - ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。 + ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。 </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta"><?php</span> - <span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">0O1</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-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> +<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> +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">'We are hiring!'</span>); +\<span class="hljs-title function_ invoke__">error_reporting</span>(~+!<span class="hljs-string">'We are hiring!'</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>) =></span> (<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$x</span></span>) =></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>) =></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>) =></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>) =></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>) =></span> \<span class="hljs-title function_ invoke__">printf</span>(<span class="hljs-string">'%c'</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>) =></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-variable">$z</span> = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$f</span></span>) =></span> (<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$x</span></span>) =></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>) =></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>) =></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>) =></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>) =></span> \<span class="hljs-title function_ invoke__">printf</span>(<span class="hljs-string">'%c'</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>) =></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>) =></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>) =></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>) =></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>) =></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>) =></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>) =></span> <span class="hljs-keyword">match</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>) =></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>) =></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>) =></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>) =></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>) =></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>) =></span> <span class="hljs-keyword">match</span> (<span class="hljs-variable">$m</span>[<span class="hljs-variable">$mp</span>]) { +!![] => [<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>) =></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>) =></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> => <span class="hljs-variable">$loop</span>(++<span class="hljs-variable">$pc</span>, ++<span class="hljs-variable">$n</span>), - <span class="hljs-variable">$e</span> => <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> => <span class="hljs-variable">$loop</span>(++<span class="hljs-variable">$pc</span>, <span class="hljs-variable">$n</span>), + <span class="hljs-variable">$b</span> => <span class="hljs-variable">$loop</span>(++<span class="hljs-variable">$pc</span>, ++<span class="hljs-variable">$n</span>), + <span class="hljs-variable">$e</span> => <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> => <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> => [<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>) =></span> <span class="hljs-keyword">match</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>) =></span> <span class="hljs-keyword">match</span> (<span class="hljs-variable">$m</span>[<span class="hljs-variable">$mp</span>]) { +!![] => [<span class="hljs-variable">$mp</span>, ++<span class="hljs-variable">$pc</span>], <span class="hljs-keyword">default</span> => [<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>) =></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>) =></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> => <span class="hljs-variable">$loop</span>(--<span class="hljs-variable">$pc</span>, ++<span class="hljs-variable">$n</span>), - <span class="hljs-variable">$b</span> => <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> => <span class="hljs-variable">$loop</span>(--<span class="hljs-variable">$pc</span>, <span class="hljs-variable">$n</span>), + <span class="hljs-variable">$e</span> => <span class="hljs-variable">$loop</span>(--<span class="hljs-variable">$pc</span>, ++<span class="hljs-variable">$n</span>), + <span class="hljs-variable">$b</span> => <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> => <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>) =></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>) =></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>) =></span> +}; +$🐘 = <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$p</span></span>) =></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>) =></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>) =></span> <span class="hljs-keyword">isset</span>(<span class="hljs-variable">$p</span>[<span class="hljs-variable">$pc</span>]) && <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>($🎪), +!![], +!![]); +)(<span class="hljs-variable">$mm</span>(+!![], +(![].![])), <span class="hljs-variable">$p</span>, <span class="hljs-variable">$id</span>($🤡), <span class="hljs-variable">$id</span>($🎪), +!![], +!![]); - $🐘([ +$🐘([ $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $🤡, $👉, $👍, $👍, $👍, @@ -147,10 +147,10 @@ $👉, $👍, $👍, $📝, $👉, $👎, $📝, $👈, $📝, - ]);</code></pre> +]);</code></pre> <p> - この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。 + この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。 </p> <section id="section--_解説"> @@ -158,14 +158,14 @@ <section id="section--_絵文字"> <h4><a href="#section--_絵文字">絵文字</a></h4> <p> - まず目につくのは大量の絵文字だろう。 PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。 + まず目につくのは大量の絵文字だろう。 PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。 </p> </section> <section id="section--_プログラム全体"> <h4><a href="#section--_プログラム全体">プログラム全体</a></h4> <p> - Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。 + Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。 </p> <p> @@ -173,16 +173,16 @@ </p> <p> - なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。 + なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。 </p> <pre class="highlight monospaced"><code>+ + + + + + + + + + [ -> + + + -> + + + + + -> + + + + + + + + + + + + -> + + + + + + + + + + -< < < < - + > + + + + > + + + + + + > + + + + + + + + + + + + + > + + + + + + + + + + + < < < < - ] > + + + + + . - - . @@ -200,11 +200,11 @@ < .</code></pre> <p> - 実行結果はこちら: <a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a> + 実行結果はこちら: <a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a> </p> <p> - それぞれの絵文字で表された関数が、各命令に対応している。 + それぞれの絵文字で表された関数が、各命令に対応している。 </p> <ul> @@ -238,45 +238,45 @@ </ul> <p> - <code>,</code> (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。 + <code>,</code> (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。 </p> <p> - なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。 + なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。 </p> </section> <section id="section--_絵文字の選択"> <h4><a href="#section--_絵文字の選択">絵文字の選択</a></h4> <p> - おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> は弊社デジタルサーカスにちなんでいる。 また、<code>$🐘</code> は PHP のマスコットの象に由来する。 + おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> は弊社デジタルサーカスにちなんでいる。 また、<code>$🐘</code> は PHP のマスコットの象に由来する。 </p> </section> <section id="section--_strict_types"> <h4><a href="#section--_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> から始まる八進数リテラルを使った。 + <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--_url"> <h4><a href="#section--_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> 以降は行コメントになっている。 + 完全に合法な PHP のコードである。 <code>https:</code> 部分はラベル、<code>//</code> 以降は行コメントになっている。 </p> </section> <section id="section--_リテラルなしで数値を生成する"> <h4><a href="#section--_リテラルなしで数値を生成する">リテラルなしで数値を生成する</a></h4> <p> - ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 PHP では、型変換を利用することで任意の整数を作り出すことができる。 + ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 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> === +!![]); @@ -286,33 +286,33 @@ <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>'10'</code>)。これに <code>+</code> を適用すると、<code>string</code> から <code>int</code> への型変換が走り、<code>10</code> が生まれる (コード量に頓着しないなら、<code>1</code> を 10 個足し合わせてももちろん 10 が作れる)。 + <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>'10'</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> にしている。 + また、<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--_if_文なしで条件分岐"> <h4><a href="#section--_if_文なしで条件分岐"><code>if</code> 文なしで条件分岐</a></h4> <p> - 三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> を一切書かずに条件分岐ができる。 また、<code>&&</code> / <code>||</code> も使えることがある。 遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code> のような形で分岐することもできる。 + 三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> を一切書かずに条件分岐ができる。 また、<code>&&</code> / <code>||</code> も使えることがある。 遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code> のような形で分岐することもできる。 </p> </section> <section id="section--_whilefor_文なしでループ"> <h4><a href="#section--_whilefor_文なしでループ"><code>while</code>、<code>for</code> 文なしでループ</a></h4> <p> - 不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。 ここでは、一般に Z コンビネータとして知られるものを使った (<code>$z</code>)。 + 不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。 ここでは、一般に Z コンビネータとして知られるものを使った (<code>$z</code>)。 </p> <p> - 実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。 + 実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。 </p> <p> - なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、 あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。 + なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、 あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。 </p> </section> </section> @@ -321,95 +321,95 @@ <section id="section--_第2問_riddle_php"> <h2><a href="#section--_第2問_riddle_php">第2問 riddle.php</a></h2> <p> - ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。 + ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。 </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta"><?php</span> - <span class="hljs-comment">/********************************************************* - * This program displays a PHPer token. * - * Guess 'N'. * - * * - * 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> <= N && N <= <span class="hljs-number">0b11111_11111_11111_11111_11111</span>); +<span class="hljs-comment">/********************************************************* +* This program displays a PHPer token. * +* Guess 'N'. * +* * +* 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> <= N && N <= <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">$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">'%025b'</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">'0'</span>, <span class="hljs-string">'1'</span>], <span class="hljs-attr">replace</span>: [<span class="hljs-string">' '</span>, <span class="hljs-string">'#'</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">"\n"</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">"<span class="hljs-subst">{$x}</span>\n\n"</span>; - }</code></pre> +<span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">sprintf</span>(<span class="hljs-string">'%025b'</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">'0'</span>, <span class="hljs-string">'1'</span>], <span class="hljs-attr">replace</span>: [<span class="hljs-string">' '</span>, <span class="hljs-string">'#'</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">"\n"</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">"<span class="hljs-subst">{$x}</span>\n\n"</span>; +}</code></pre> <p> - さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 トークンを得るためには、ソースコードを読み、定数 <code>N</code> を特定する必要がある。 + さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 トークンを得るためには、ソースコードを読み、定数 <code>N</code> を特定する必要がある。 </p> <p> - ここでは、私の想定解を解説する。 + ここでは、私の想定解を解説する。 </p> <section id="section--_読解"> <h3><a href="#section--_読解">読解</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> +<span class="hljs-comment">// 略</span> +];</code></pre> <p> - 数値からなる <code>$token</code> があり、各要素をループしている。 + 数値からなる <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> + <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) を取り、 + まずは排他的論理和 (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">'%025b'</span>, <span class="hljs-variable">$x</span>);</code></pre> + <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">'%025b'</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">'0'</span>, <span class="hljs-string">'1'</span>], <span class="hljs-attr">replace</span>: [<span class="hljs-string">' '</span>, <span class="hljs-string">'#'</span>], <span class="hljs-attr">subject</span>: <span class="hljs-variable">$x</span>);</code></pre> + <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">'0'</span>, <span class="hljs-string">'1'</span>], <span class="hljs-attr">replace</span>: [<span class="hljs-string">' '</span>, <span class="hljs-string">'#'</span>], <span class="hljs-attr">subject</span>: <span class="hljs-variable">$x</span>);</code></pre> <p> - 0 を空白に、1 を <code>#</code> にし、 + 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">"\n"</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> + <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">"\n"</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文字ごとに区切ったあと、改行で結合している。 + 5文字ごとに区切ったあと、改行で結合している。 </p> </section> <section id="section--_ヒント"> <h3><a href="#section--_ヒント">ヒント</a></h3> <p> - 次に、ソースコードに書いてあるヒントを読んでいく。 + 次に、ソースコードに書いてあるヒントを読んでいく。 </p> <ul> @@ -431,45 +431,45 @@ </ul> <p> - ここで、PHPer トークンは必ず <code>#</code> 記号から始まることを思いだすと、 <code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code>#</code> になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。 + ここで、PHPer トークンは必ず <code>#</code> 記号から始まることを思いだすと、 <code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code>#</code> になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。 </p> </section> <section id="section--_解く"> <h3><a href="#section--_解く">解く</a></h3> <p> - ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> に変換されるような <code>N</code> を見つければよい。 + ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> に変換されるような <code>N</code> を見つければよい。 </p> <p> - <code>N</code> は高々 + <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> <= N && N <= <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"><?php</span> - <span class="hljs-variable">$x</span> = <span class="hljs-number">0x14B499C</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-variable">$x</span> ^ N; - <span class="hljs-variable">$x</span> = <span class="hljs-title function_ invoke__">sprintf</span>(<span class="hljs-string">'%025b'</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">'0'</span>, <span class="hljs-string">'1'</span>], <span class="hljs-attr">replace</span>: [<span class="hljs-string">' '</span>, <span class="hljs-string">'#'</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">"\n"</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-variable">$x</span> = <span class="hljs-title function_ invoke__">sprintf</span>(<span class="hljs-string">'%025b'</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">'0'</span>, <span class="hljs-string">'1'</span>], <span class="hljs-attr">replace</span>: [<span class="hljs-string">' '</span>, <span class="hljs-string">'#'</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">"\n"</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">" # # \n"</span> . - <span class="hljs-string">"#####\n"</span> . - <span class="hljs-string">" # # \n"</span> . - <span class="hljs-string">"#####\n"</span> . - <span class="hljs-string">" # # "</span>);</code></pre> +<span class="hljs-title function_ invoke__">assert</span>(<span class="hljs-variable">$x</span> === +<span class="hljs-string">" # # \n"</span> . +<span class="hljs-string">"#####\n"</span> . +<span class="hljs-string">" # # \n"</span> . +<span class="hljs-string">"#####\n"</span> . +<span class="hljs-string">" # # "</span>);</code></pre> <p> - この一連の変換に対する逆変換を考えると、次のようになる。 + この一連の変換に対する逆変換を考えると、次のようになる。 </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta"><?php</span> @@ -490,7 +490,7 @@ <span class="hljs-keyword">echo</span> <span class="hljs-string">"N = <span class="hljs-subst">$n</span>\n"</span>;</code></pre> <p> - これを実行すると、<code>N</code> が得られる。 + これを実行すると、<code>N</code> が得られる。 </p> </section> </section> @@ -498,47 +498,47 @@ <section id="section--_第3問_toquine_php"> <h2><a href="#section--_第3問_toquine_php">第3問 toquine.php</a></h2> <p> - ソースコードはこちら。 + ソースコードはこちら。 </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta"><?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-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> = <<<<span class="hljs-string">'Q'</span> - <span class="hljs-meta"><?</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> <= <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">"\a"</span>, <span class="hljs-title function_ invoke__">fge_fcyvg</span>(<span class="hljs-title function_ invoke__">fge_ercynpr</span>([<span class="hljs-string">'0'</span>,<span class="hljs-string">'1'</span>], [<span class="hljs-string">' '</span>,<span class="hljs-string">'##'</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">'025o'</span>, <span class="hljs-variable">$kf</span>[<span class="hljs-variable">$v</span>])), <span class="hljs-number">012</span>)) . <span class="hljs-string">"\a\a"</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>) => <span class="hljs-title function_ invoke__">vzcybqr</span>(<span class="hljs-string">', '</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>) => <span class="hljs-title function_ invoke__">fcevags</span>(<span class="hljs-string">'0k'</span> . <span class="hljs-title function_ invoke__">pue</span>(<span class="hljs-number">37</span>) . <span class="hljs-string">'07K'</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">"<<<'Q'\a<span class="hljs-subst">{$f}</span>\aQ"</span>), <span class="hljs-title function_ invoke__">vzcybqr</span>(<span class="hljs-string">",\a"</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> <= <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">"\n"</span>, <span class="hljs-title function_ invoke__">str_split</span>(<span class="hljs-title function_ invoke__">str_replace</span>([<span class="hljs-string">'0'</span>,<span class="hljs-string">'1'</span>], [<span class="hljs-string">' '</span>,<span class="hljs-string">'##'</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">'025b'</span>, <span class="hljs-variable">$xs</span>[<span class="hljs-variable">$i</span>])), <span class="hljs-number">012</span>)) . <span class="hljs-string">"\n\n"</span>; - <span class="hljs-variable">$ws</span> = <span class="hljs-title function_ invoke__">array_map</span>(fn(<span class="hljs-variable">$w</span>) => <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-string">', '</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>) => <span class="hljs-title function_ invoke__">sprintf</span>(<span class="hljs-string">'0x'</span> . <span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-number">37</span>) . <span class="hljs-string">'07X'</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">"<<<'D'\n<span class="hljs-subst">{$s}</span>\nD"</span>), <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-string">",\n"</span>, <span class="hljs-variable">$ws</span>));</code></pre> +<span class="hljs-variable">$s</span> = <<<<span class="hljs-string">'Q'</span> +<span class="hljs-meta"><?</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> <= <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">"\a"</span>, <span class="hljs-title function_ invoke__">fge_fcyvg</span>(<span class="hljs-title function_ invoke__">fge_ercynpr</span>([<span class="hljs-string">'0'</span>,<span class="hljs-string">'1'</span>], [<span class="hljs-string">' '</span>,<span class="hljs-string">'##'</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">'025o'</span>, <span class="hljs-variable">$kf</span>[<span class="hljs-variable">$v</span>])), <span class="hljs-number">012</span>)) . <span class="hljs-string">"\a\a"</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>) => <span class="hljs-title function_ invoke__">vzcybqr</span>(<span class="hljs-string">', '</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>) => <span class="hljs-title function_ invoke__">fcevags</span>(<span class="hljs-string">'0k'</span> . <span class="hljs-title function_ invoke__">pue</span>(<span class="hljs-number">37</span>) . <span class="hljs-string">'07K'</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">"<<<'Q'\a<span class="hljs-subst">{$f}</span>\aQ"</span>), <span class="hljs-title function_ invoke__">vzcybqr</span>(<span class="hljs-string">",\a"</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> <= <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">"\n"</span>, <span class="hljs-title function_ invoke__">str_split</span>(<span class="hljs-title function_ invoke__">str_replace</span>([<span class="hljs-string">'0'</span>,<span class="hljs-string">'1'</span>], [<span class="hljs-string">' '</span>,<span class="hljs-string">'##'</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">'025b'</span>, <span class="hljs-variable">$xs</span>[<span class="hljs-variable">$i</span>])), <span class="hljs-number">012</span>)) . <span class="hljs-string">"\n\n"</span>; +<span class="hljs-variable">$ws</span> = <span class="hljs-title function_ invoke__">array_map</span>(fn(<span class="hljs-variable">$w</span>) => <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-string">', '</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>) => <span class="hljs-title function_ invoke__">sprintf</span>(<span class="hljs-string">'0x'</span> . <span class="hljs-title function_ invoke__">chr</span>(<span class="hljs-number">37</span>) . <span class="hljs-string">'07X'</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">"<<<'D'\n<span class="hljs-subst">{$s}</span>\nD"</span>), <span class="hljs-title function_ invoke__">implode</span>(<span class="hljs-string">",\n"</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--_解説_2"> @@ -546,53 +546,53 @@ <section id="section--_プログラム全体_2"> <h4><a href="#section--_プログラム全体_2">プログラム全体</a></h4> <p> - コメントにもあるとおり、これは quine (風) のプログラムになっている。 Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。 + コメントにもあるとおり、これは quine (風) のプログラムになっている。 Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。 </p> <p> - このプログラムは、実行すると自身とほとんど同じプログラムを出力する。 異なるのはトークンになっている部分のみである。 + このプログラムは、実行すると自身とほとんど同じプログラムを出力する。 異なるのはトークンになっている部分のみである。 </p> </section> <section id="section--_トークン"> <h4><a href="#section--_トークン">トークン</a></h4> <p> - <code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> とほぼ同じなので省略する。 + <code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> とほぼ同じなので省略する。 </p> </section> <section id="section--_状態保持"> <h4><a href="#section--_状態保持">状態保持</a></h4> <p> - トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。 このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code><em>LINE</em></code> から情報を取得している。 + トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。 このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code><em>LINE</em></code> から情報を取得している。 </p> </section> <section id="section--_rot_13"> <h4><a href="#section--_rot_13">ROT 13</a></h4> <p> - Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。 これがあまり美しくないので、<code>toquine.php</code> では、ROT 13 変換を使って難読化した。 + Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。 これがあまり美しくないので、<code>toquine.php</code> では、ROT 13 変換を使って難読化した。 </p> <p> - それにしてもなぜこんなものが標準ライブラリに……。 + それにしてもなぜこんなものが標準ライブラリに……。 </p> </section> </section> </section> - <section id="section--_おわりに"> - <h2><a href="#section--_おわりに">おわりに</a></h2> + <section id="section--outro"> + <h2><a href="#section--outro">おわりに</a></h2> <p> - 解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。 + 解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。 </p> <p> - 今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、 来年は 5問、より面白い問題を持っていきます。 + 今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、 来年は 5問、より面白い問題を持っていきます。 </p> <p> - 実はもう作りはじめているので、どうか来年もありますように……。 + 実はもう作りはじめているので、どうか来年もありますように……。 </p> </section> </div> diff --git a/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html b/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html index db21a3d..cd997f7 100644 --- a/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html +++ b/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html @@ -8,7 +8,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -50,54 +50,54 @@ </li> </ol> </section> - <section id="section--_はじめに"> - <h2><a href="#section--_はじめに">はじめに</a></h2> + <section id="section--intro"> + <h2><a href="#section--intro">はじめに</a></h2> <p> - こんなものを作った。 + こんなものを作った。 </p> <pre class="highlight monospaced"><code>$ term-banner 'Hello, World!' 'こんにちは、' '世界!'</code></pre> <p> - image::https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png[term-banner のスクリーンショット] + 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> + リポジトリはこちら: <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> よりも大きく現在時刻を表示する。 + 以前、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 会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。 こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。 + <code>big-clock-mode</code> を開発したのは、次のようなシチュエーションで使うためである。 弊社では現在リモートワークが基本だが、web 会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。 こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。 </p> <p> - それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。 + それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。 </p> <p> - しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。 どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。 + しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。 どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。 </p> <p> - そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。 まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。 + そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。 まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。 </p> </section> <section id="section--_プログラム"> <h2><a href="#section--_プログラム">プログラム</a></h2> <p> - 全体の流れは次のようになっている。 + 全体の流れは次のようになっている。 </p> <ol numeration="arabic"> @@ -115,45 +115,45 @@ </ol> <p> - <code>big-clock-mode</code> が Go 製なので、今回も Go で書いた。 PNG が標準ライブラリにあったり、Shift-JIS のエンコーディングが準標準ライブラリにあったりしたのは助かった。 + <code>big-clock-mode</code> が Go 製なので、今回も Go で書いた。 PNG が標準ライブラリにあったり、Shift-JIS のエンコーディングが準標準ライブラリにあったりしたのは助かった。 </p> <p> - フォントファイルは <code>go:embed</code> で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。 仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。 + フォントファイルは <code>go:embed</code> で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。 仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。 </p> </section> <section id="section--_フォント"> <h2><a href="#section--_フォント">フォント</a></h2> <p> - フリーの 8x8 ビットマップフォントである、https://littlelimit.net/misaki.htm[美咲フォント 2021-05-05a 版] を使わせていただいた。 + フリーの 8x8 ビットマップフォントである、https://littlelimit.net/misaki.htm[美咲フォント 2021-05-05a 版] を使わせていただいた。 </p> <p> - はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。 同じく 8x8 で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。 + はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。 同じく 8x8 で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。 </p> <p> - 美咲フォントは、平仮名・片仮名に留まらず、JIS 第一・第二水準の漢字までサポートしている。 第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。 + 美咲フォントは、平仮名・片仮名に留まらず、JIS 第一・第二水準の漢字までサポートしている。 第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。 </p> <p> - さらに言うと、実のところ美咲フォントは実サイズ 7x7 で作られており、余白が設けられている。 これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。 おかげでコーディングまで楽になった。 + さらに言うと、実のところ美咲フォントは実サイズ 7x7 で作られており、余白が設けられている。 これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。 おかげでコーディングまで楽になった。 </p> <p> - ゴシック体と明朝体があったが、私の好みで明朝体の方にした。 ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。 + ゴシック体と明朝体があったが、私の好みで明朝体の方にした。 ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。 </p> <p> - 2022-04-27 追記: <code>-f</code> オプションで選べるようにした。 + 2022-04-27 追記: <code>-f</code> オプションで選べるようにした。 </p> </section> - <section id="section--_おわりに"> - <h2><a href="#section--_おわりに">おわりに</a></h2> + <section id="section--outro"> + <h2><a href="#section--outro">おわりに</a></h2> <p> - あなたもターミナルに住んでみませんか? + あなたもターミナルに住んでみませんか? </p> </section> </div> diff --git a/public/posts/2022-05-01/phperkaigi-2022/index.html b/public/posts/2022-05-01/phperkaigi-2022/index.html index 9082b47..f4c89fa 100644 --- a/public/posts/2022-05-01/phperkaigi-2022/index.html +++ b/public/posts/2022-05-01/phperkaigi-2022/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -59,14 +59,14 @@ </li> </ol> </section> - <section id="section--_はじめに"> - <h2><a href="#section--_はじめに">はじめに</a></h2> + <section id="section--intro"> + <h2><a href="#section--intro">はじめに</a></h2> <p> - 2022-04-09 から 2022-04-11 にかけて開催された、https://phperkaigi.jp/2022/[PHPerKaigi 2022] に、一般参加者として参加した。 弊社https://www.dgcircus.com/[デジタルサーカス株式会社] はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。 + 2022-04-09 から 2022-04-11 にかけて開催された、https://phperkaigi.jp/2022/[PHPerKaigi 2022] に、一般参加者として参加した。 弊社https://www.dgcircus.com/[デジタルサーカス株式会社] はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。 </p> <p> - 昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。 + 昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。 </p> </section> @@ -75,7 +75,7 @@ <section id="section--_厳選おすすめトーク"> <h3><a href="#section--_厳選おすすめトーク">厳選おすすめトーク</a></h3> <p> - 多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。 + 多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。 </p> <p> @@ -84,11 +84,11 @@ <blockquote> <p> - PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。 + PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。 </p> <p> - 本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。 + 本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。 </p> </blockquote> @@ -98,11 +98,11 @@ <blockquote> <p> - PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice 理解していますか? + PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice 理解していますか? <br> これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります! <br> - またそれらを理解した上でのエラーハンドリングを学びましょう。 + またそれらを理解した上でのエラーハンドリングを学びましょう。 </p> </blockquote> @@ -112,13 +112,13 @@ <blockquote> <p> - 毎日流れてくるエラーに皆さんはどう向き合ってますか? + 毎日流れてくるエラーに皆さんはどう向き合ってますか? <br> エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。 <br> サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、 <br> - エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。 + エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。 </p> </blockquote> @@ -128,11 +128,11 @@ <blockquote> <p> - 昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。 + 昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。 </p> <p> - 最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には + 最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には <br> ・「(私の思う)良い設計」を実現するための意思決定 <br> @@ -140,11 +140,11 @@ <br> ・移植中に遭遇したトラブルとその解決策 <br> - といった文脈や葛藤が存在しています。 + といった文脈や葛藤が存在しています。 </p> <p> - 本発表はそれらを共有することで + 本発表はそれらを共有することで <br> ・PHPアプリケーションの設計、実装事例として役立ててもらう <br> @@ -152,7 +152,7 @@ <br> ・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう <br> - ことを目的とします。 + ことを目的とします。 </p> </blockquote> @@ -162,15 +162,15 @@ <blockquote> <p> - サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。 + サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。 </p> <p> - フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。 + フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。 </p> <p> - このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。 + このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。 </p> </blockquote> </section> @@ -178,7 +178,7 @@ <section id="section--_トークン問題の作成"> <h3><a href="#section--_トークン問題の作成">トークン問題の作成</a></h3> <p> - 今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。 + 今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。 </p> </section> @@ -187,36 +187,36 @@ <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> をいただいた。 + また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a> をいただいた。 </p> </section> <section id="section--_カンファレンス全体への感想"> <h3><a href="#section--_カンファレンス全体への感想">カンファレンス全体への感想</a></h3> <p> - <a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> では、こんなことを書いた。 + <a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> では、こんなことを書いた。 </p> <blockquote> <p> - 1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 + 1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 <br> - まあ初カンファレンスだし、とお茶を濁しておこう。 + まあ初カンファレンスだし、とお茶を濁しておこう。 </p> </blockquote> <p> - この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。 + この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。 <br> - これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。 + これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。 </p> <p> - なお、アンカンファレンスについては、1日目の終わりにhttps://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e[トークン問題の解説放送]もおこなった。 + なお、アンカンファレンスについては、1日目の終わりにhttps://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e[トークン問題の解説放送]もおこなった。 </p> <p> - また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。 今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。 + また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。 今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。 </p> </section> </section> @@ -224,7 +224,7 @@ <section id="section--_そして来年へ"> <h2><a href="#section--_そして来年へ">そして来年へ……?</a></h2> <p> - PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。 + PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。 </p> <ul> @@ -251,11 +251,11 @@ </p> <p> - 最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。 + 最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。 </p> <p> - ではまた来年。 + ではまた来年。 </p> </section> </div> diff --git a/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html b/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html index 2aa8c03..0fb3911 100644 --- a/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html +++ b/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -59,18 +59,18 @@ </li> </ol> </section> - <section id="section--_はじめに"> - <h2><a href="#section--_はじめに">はじめに</a></h2> + <section id="section--intro"> + <h2><a href="#section--intro">はじめに</a></h2> <p> - 本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a> が開催された (らしい)。 + 本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a> が開催された (らしい)。 </p> <p> - カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。 + カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。 </p> <p> - ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</a> + ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</a> <br> スライド: <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> </p> @@ -79,7 +79,7 @@ <section id="section--_解"> <h2><a href="#section--_解">解</a></h2> <p> - 細かいレギュレーションは不明だったので、勝手に定めた。 + 細かいレギュレーションは不明だったので、勝手に定めた。 </p> <ul> @@ -109,28 +109,28 @@ </ul> <p> - 書いたものがこちら: + 書いたものがこちら: </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">[<span class="hljs-meta"><?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>>=<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">', '</span>,<span class="hljs-variable">$r</span>??[]);<span class="hljs-meta">?></span>]</code></pre> <p> - しめて 123 バイトとなった (末尾改行を含めずにカウント)。 + しめて 123 バイトとなった (末尾改行を含めずにカウント)。 </p> <p> - こちらは改行とスペースを追加したバージョン: + こちらは改行とスペースを追加したバージョン: </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">[<span class="hljs-meta"><?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-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> >= <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">', '</span>, <span class="hljs-variable">$r</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">', '</span>, <span class="hljs-variable">$r</span> ?? []); - <span class="hljs-meta">?></span>]</code></pre> +<span class="hljs-meta">?></span>]</code></pre> </section> <section id="section--_使用したテクニック"> @@ -138,44 +138,44 @@ <section id="section--_指数表記"> <h3><a href="#section--_指数表記">指数表記</a></h3> <p> - 割と多くの言語のゴルフで使えるテクニック。<code>e</code> を用いた指数表記で、大きな数を短く表す。このコードでは <code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。 + 割と多くの言語のゴルフで使えるテクニック。<code>e</code> を用いた指数表記で、大きな数を短く表す。このコードでは <code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。 </p> </section> <section id="section--_foreach_や_for_の中身を1つの文に"> <h3><a href="#section--_foreach_や_for_の中身を1つの文に">foreach や for の中身を1つの文に</a></h3> <p> - <code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、通常 <code>{</code> を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code> を省略できる。C言語などでも使える。 + <code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、通常 <code>{</code> を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code> を省略できる。C言語などでも使える。 </p> </section> <section id="section--_r_に初期値を入れない"> <h3><a href="#section--_r_に初期値を入れない">$r に初期値を入れない</a></h3> <p> - PHP では、<code>$r[] = &#8230;&#8203;</code> のような配列の末尾に追加する式を実行したとき、<code>$r</code> が未定義だった場合は <code>$r</code> を勝手に定義して空の配列で初期化してくれる。これを利用すると、<code>$r = [];</code> のような初期化が不要になる。 + PHP では、<code>$r[] = &#8230;&#8203;</code> のような配列の末尾に追加する式を実行したとき、<code>$r</code> が未定義だった場合は <code>$r</code> を勝手に定義して空の配列で初期化してくれる。これを利用すると、<code>$r = [];</code> のような初期化が不要になる。 </p> <p> - ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code> が未定義になってしまい、<code>implode()</code> に渡すところでエラーになる。それを防ぐために <code>$r ?? []</code> を使っている。 + ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code> が未定義になってしまい、<code>implode()</code> に渡すところでエラーになる。それを防ぐために <code>$r ?? []</code> を使っている。 </p> <p> - もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。 + もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。 </p> </section> <section id="section--_php_タグの外に文字列を置く"> <h3><a href="#section--_php_タグの外に文字列を置く">PHP タグの外に文字列を置く</a></h3> <p> - PHP では、<code><?php</code> <code>?></code> で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず <code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。 + PHP では、<code><?php</code> <code>?></code> で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず <code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。 </p> </section> </section> - <section id="section--_おわりに"> - <h2><a href="#section--_おわりに">おわりに</a></h2> + <section id="section--outro"> + <h2><a href="#section--outro">おわりに</a></h2> <p> - 最後になりましたが、https://twitter.com/m3m0r7[めもりー] さん、楽しい問題をありがとうございました。 + 最後になりましたが、https://twitter.com/m3m0r7[めもりー] さん、楽しい問題をありがとうございました。 </p> </section> </div> diff --git a/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html b/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html index 87996f1..30c0019 100644 --- a/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html +++ b/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html @@ -8,7 +8,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -47,62 +47,62 @@ </li> </ol> </section> - <section id="section--_はじめに"> - <h2><a href="#section--_はじめに">はじめに</a></h2> + <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 の寄付をおこないました。 + 先日、私の勤める <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> + 記事: <a href="https://www.dgcircus.com/news/581">https://www.dgcircus.com/news/581</a> </p> <p> - 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。 + 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。 </p> </section> <section id="section--_なぜ"> <h2><a href="#section--_なぜ">なぜ?</a></h2> <p> - 組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。 + 組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。 </p> <p> - 当時の考えを端的にまとめた社内チャットの投稿があったので、それを引用します: + 当時の考えを端的にまとめた社内チャットの投稿があったので、それを引用します: </p> <blockquote> <p> - 結局これを通したい (私の中での) 最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、寄付の報告が流れてきたり、OSS のフリーライドの話が流れてきたりするたびに、自尊心が毀損される、というか (これは大袈裟すぎる表現で、実際にはそこまで明確に傷ついているわけではありませんが)。 + 結局これを通したい (私の中での) 最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、寄付の報告が流れてきたり、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>) といった行為は、コミュニティへの貢献であると同時に、社員に対する精神的福利厚生でもあると言えるでしょう (知らんけど)。これらは、技術や技術者を大切にする組織である、ということの、対外的にも対内的にも強力なメッセージなのです。 + 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--_おわりに"> - <h2><a href="#section--_おわりに">おわりに</a></h2> + <section id="section--outro"> + <h2><a href="#section--outro">おわりに</a></h2> <p> - 最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。この場を借りて感謝申し上げます。 + 最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。この場を借りて感謝申し上げます。 </p> </section> </div> diff --git a/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html index 42931a5..23028a3 100644 --- a/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html +++ b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -59,14 +59,14 @@ <section id="section--_記事の構成について"> <h2><a href="#section--_記事の構成について">記事の構成について</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> にソースコードがあるので、そちらを先に見てほしい。 + この記事は、普通の 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--_レギュレーション"> <h2><a href="#section--_レギュレーション">レギュレーション</a></h2> <p> - PHP で、次のような制約の下に fizzbuzz を書いた。 + PHP で、次のような制約の下に fizzbuzz を書いた。 </p> <ul> @@ -106,18 +106,18 @@ </ul> <p> - 備考: PHP には <code>short_open_tag</code> というオプションがあり、これを有効にするとファイル冒頭の <code><?php</code> の代わりに <code><?</code> を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト off になっている環境が多いようなので、今回は使わないことにした。 + 備考: PHP には <code>short_open_tag</code> というオプションがあり、これを有効にするとファイル冒頭の <code><?php</code> の代わりに <code><?</code> を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト off になっている環境が多いようなので、今回は使わないことにした。 </p> </section> <section id="section--_主な障害"> <h2><a href="#section--_主な障害">主な障害</a></h2> <p> - 1行あたりの文字数など、適当に改行を挟めばいいだけではないのか? + 1行あたりの文字数など、適当に改行を挟めばいいだけではないのか? </p> <p> - 特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。 + 特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。 </p> <pre class="highlight" language="c" linenumbering="unnumbered"><code class="highlight">#\ @@ -128,7 +128,7 @@ l\ u\ d\ e\ -&lt;\ +<\ s\ t\ d\ @@ -136,7 +136,7 @@ i\ o\ .\ h\ -&gt;\ +>\ <span class="hljs-comment">/* */</span> i\ @@ -159,7 +159,7 @@ t\ */</span> i= <span class="hljs-number">1</span>; -i&lt; +i< <span class="hljs-number">1</span>\ <span class="hljs-number">0</span>\ <span class="hljs-number">0</span>; @@ -196,15 +196,15 @@ c\ <span class="hljs-comment">/* あとは同じように普通のプログラムを変形するだけなので省略 */</span></code></pre> <p> - バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。 + バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。 </p> <p> - さて、PHP ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、<code>echo</code> で出力することや、<code>for</code> でループすること、<code>new</code> でインスタンスを生成することができない。特に、出力は fizzbuzz をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。 + さて、PHP ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、<code>echo</code> で出力することや、<code>for</code> でループすること、<code>new</code> でインスタンスを生成することができない。特に、出力は fizzbuzz をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。 </p> <p> - 当然、名前が3文字以上ある関数も使えない。なお、標準 PHP の範囲内において、名前が 2文字以下の関数は以下のとおりである: + 当然、名前が3文字以上ある関数も使えない。なお、標準 PHP の範囲内において、名前が 2文字以下の関数は以下のとおりである: </p> <ul> @@ -222,11 +222,11 @@ c\ </ul> <p> - (環境によって多少は変わるかも) + (環境によって多少は変わるかも) </p> <p> - 2文字の関数を定義しまくった拡張モジュールを用意しておいて <code>dl()</code> で読み込む行為は、レギュレーションで定めた + 2文字の関数を定義しまくった拡張モジュールを用意しておいて <code>dl()</code> で読み込む行為は、レギュレーションで定めた </p> <blockquote> @@ -238,11 +238,11 @@ c\ </blockquote> <p> - に反する (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。 + に反する (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。 </p> <p> - また、2文字だと文字列がまともに書けないのも辛い。<code>''</code> だけで 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので + また、2文字だと文字列がまともに書けないのも辛い。<code>''</code> だけで 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$a</span> @@ -251,11 +251,11 @@ a'</span> ;;</code></pre> <p> - とすると <code>$a</code> は <code>"\na"</code> になるのだが、余計な改行が入ってしまう。 + とすると <code>$a</code> は <code>"\na"</code> になるのだが、余計な改行が入ってしまう。 </p> <p> - これらの障害をどのように乗り越えるのか、次節から見ていく。 + これらの障害をどのように乗り越えるのか、次節から見ていく。 </p> </section> @@ -264,47 +264,47 @@ a'</span> <section id="section--_普通の_fizzbuzz"> <h3><a href="#section--_普通の_fizzbuzz">普通の (?) fizzbuzz</a></h3> <p> - まずは普通に書くとしよう。 + まずは普通に書くとしよう。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">&lt;?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta"><?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">for</span> (<span class="hljs-variable">$i</span> = <span class="hljs-number">1</span>; <span class="hljs-variable">$i</span> < <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">''</span> : <span class="hljs-string">'Fizz'</span>) . (<span class="hljs-variable">$i</span> % <span class="hljs-number">5</span> ? <span class="hljs-string">''</span> : <span class="hljs-string">'Buzz'</span>) ?: <span class="hljs-variable">$i</span>) . <span class="hljs-string">"\n"</span>; }</code></pre> <p> - 素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。 + 素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。 </p> </section> <section id="section--_for_の排除"> <h3><a href="#section--_for_の排除"><code>for</code> の排除</a></h3> <p> - <code>for</code> は、3文字もある長いキーワードである。こんなものは使えない。<code>array_</code> 系の関数を使って、適当に置き換えるとしよう。 + <code>for</code> は、3文字もある長いキーワードである。こんなものは使えない。<code>array_</code> 系の関数を使って、適当に置き換えるとしよう。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">&lt;?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta"><?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; + fn(<span class="hljs-variable">$i</span>) => <span class="hljs-title function_ invoke__">printf</span>(((<span class="hljs-variable">$i</span> % <span class="hljs-number">3</span> ? <span class="hljs-string">''</span> : <span class="hljs-string">'Fizz'</span>) . (<span class="hljs-variable">$i</span> % <span class="hljs-number">5</span> ? <span class="hljs-string">''</span> : <span class="hljs-string">'Buzz'</span>) ?: <span class="hljs-variable">$i</span>) . <span class="hljs-string">"\n"</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> に置き換えた。 + <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--_関数呼び出しの短縮"> <h3><a href="#section--_関数呼び出しの短縮">関数呼び出しの短縮</a></h3> <p> - <code>range</code>、<code>array_walk</code>、<code>printf</code> は長すぎるのでどうにかせねばならない。ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。 + <code>range</code>、<code>array_walk</code>、<code>printf</code> は長すぎるのでどうにかせねばならない。ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">&lt;?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta"><?php</span> <span class="hljs-variable">$r</span> = <span class="hljs-string">'range'</span>; <span class="hljs-variable">$w</span> = <span class="hljs-string">'array_walk'</span>; @@ -313,19 +313,19 @@ a'</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>) =&<span class="hljs-title">gt</span></span>; + <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$i</span></span>) =></span> <span class="hljs-variable">$p</span>(((<span class="hljs-variable">$i</span> % <span class="hljs-number">3</span> ? <span class="hljs-string">''</span> : <span class="hljs-string">'Fizz'</span>) . (<span class="hljs-variable">$i</span> % <span class="hljs-number">5</span> ? <span class="hljs-string">''</span> : <span class="hljs-string">'Buzz'</span>) ?: <span class="hljs-variable">$i</span>) . <span class="hljs-string">"\n"</span>), );</code></pre> <p> - これで関数を呼び出している所は短くなった。では、<code>$r</code> や <code>$w</code> や <code>$p</code>、また <code>'Fizz'</code> や <code>'Buzz'</code> はどうやって 1行2文字に収めるのか。次のテクニックへ移ろう。 + これで関数を呼び出している所は短くなった。では、<code>$r</code> や <code>$w</code> や <code>$p</code>、また <code>'Fizz'</code> や <code>'Buzz'</code> はどうやって 1行2文字に収めるのか。次のテクニックへ移ろう。 </p> </section> <section id="section--_余談_php_8_x_で動作しなくてもいいなら"> <h3><a href="#section--_余談_php_8_x_で動作しなくてもいいなら">余談: PHP 8.x で動作しなくてもいいなら</a></h3> <p> - 今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。 + 今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。 </p> <blockquote> @@ -337,7 +337,7 @@ a'</span> </blockquote> <p> - というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。例えば、 <code>Fizz</code> という文字列が欲しければ、次のようにする。 + というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。例えば、 <code>Fizz</code> という文字列が欲しければ、次のようにする。 </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$f</span> @@ -348,7 +348,7 @@ a'</span> ;;</code></pre> <p> - こうして簡単に文字列を作れる。なお、この仕様は 7.x 時点でも警告を受けるので、<code>@</code> 演算子を使って抑制してやるとよい。 + こうして簡単に文字列を作れる。なお、この仕様は 7.x 時点でも警告を受けるので、<code>@</code> 演算子を使って抑制してやるとよい。 </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$f</span> @@ -362,18 +362,18 @@ F. ;;</code></pre> <p> - むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。 + むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。 </p> </section> <section id="section--_文字列リテラルの短縮"> <h3><a href="#section--_文字列リテラルの短縮">文字列リテラルの短縮</a></h3> <p> - 実際に使った手法の説明に移る。 + 実際に使った手法の説明に移る。 </p> <p> - ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 (<code>&</code>、<code>|</code>、<code>^</code>) をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。 + ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 (<code>&</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">"12345"</span>; @@ -381,15 +381,15 @@ F. <span class="hljs-comment">// $a ^ $b は次のコードと同じ</span> <span class="hljs-variable">$result</span> = <span class="hljs-string">''</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">for</span> (<span class="hljs-variable">$i</span> = <span class="hljs-number">0</span>; <span class="hljs-variable">$i</span> < <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> +<span class="hljs-comment">// => 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">"x\nOm\n"</span>; @@ -398,7 +398,7 @@ F. <span class="hljs-keyword">echo</span> <span class="hljs-string">"<span class="hljs-subst">$r</span>\n"</span>;</code></pre> <p> - 実行すると、<code>range</code> が表示される。さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。書きかえてみよう。 + 実行すると、<code>range</code> が表示される。さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。書きかえてみよう。 </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$x</span> @@ -415,7 +415,7 @@ o'</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"<span class="hljs-subst">$r</span>\n"</span>;</code></pre> <p> - さらに <code>#</code> を使って適当に調整すると、次のようになる。 + さらに <code>#</code> を使って適当に調整すると、次のようになる。 </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$x</span> @@ -438,11 +438,11 @@ o'</span> <span class="hljs-keyword">echo</span> <span class="hljs-string">"<span class="hljs-subst">$r</span>\n"</span>;</code></pre> <p> - 1行あたり2文字で、<code>range</code> という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。 + 1行あたり2文字で、<code>range</code> という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。 </p> <p> - 備考: <code>Buzz</code> 中にある小文字の <code>u</code> は、このロジックだと non-printable な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。 + 備考: <code>Buzz</code> 中にある小文字の <code>u</code> は、このロジックだと non-printable な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。 </p> </section> </section> @@ -450,10 +450,10 @@ o'</span> <section id="section--_完成系"> <h2><a href="#section--_完成系">完成系</a></h2> <p> - 完成したものがこちら。 + 完成したものがこちら。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">&lt;?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta"><?php</span> <span class="hljs-variable">$x</span> =<span class="hljs-comment">#</span> @@ -577,7 +577,7 @@ _! (<span class="hljs-params"># <span class="hljs-variable">$i</span> </span>)# -=&<span class="hljs-title">gt</span></span>; +=></span> <span class="hljs-variable">$p</span> (( (<span class="hljs-comment">#</span> @@ -607,21 +607,21 @@ _! <section id="section--_感想など"> <h2><a href="#section--_感想など">感想など</a></h2> <p> - PHP は、スクリプト言語の中だとシンタックスシュガーが少ない (体感)。この挑戦は不可能に思われたが、PHP マニュアルとにらめっこしていたらなんとかなった。 + PHP は、スクリプト言語の中だとシンタックスシュガーが少ない (体感)。この挑戦は不可能に思われたが、PHP マニュアルとにらめっこしていたらなんとかなった。 </p> <p> - みんなもプログラムを細長くしよう。 + みんなもプログラムを細長くしよう。 </p> </section> <section id="section--_余談2_別解"> <h2><a href="#section--_余談2_別解">余談2: 別解</a></h2> <p> - PHP では、バッククォートを使ってシェルを呼び出せる。これは <code>shell_exec</code> 関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。 + PHP では、バッククォートを使ってシェルを呼び出せる。これは <code>shell_exec</code> 関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">&lt;?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta"><?php</span> <span class="hljs-title function_ invoke__">printf</span>(` e\ @@ -635,11 +635,11 @@ o\ `);</code></pre> <p> - なお、ここでは簡単のため出力に <code>printf</code> をそのまま使っているが、実際には <code>printf</code> という文字列を合成して可変関数で呼び出す。 + なお、ここでは簡単のため出力に <code>printf</code> をそのまま使っているが、実際には <code>printf</code> という文字列を合成して可変関数で呼び出す。 </p> <p> - ただし、これでは + ただし、これでは </p> <blockquote> @@ -651,14 +651,14 @@ o\ </blockquote> <p> - に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。 + に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。 </p> <p> - もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。 + もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">&lt;?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta"><?php</span> <span class="hljs-variable">$c</span> = <span class="hljs-string">'chr'</span>; @@ -689,7 +689,7 @@ ${ `);</code></pre> <p> - 先程と同じく、<code>chr</code> や <code>printf</code> を生成する部分は長くなるので省いた。 + 先程と同じく、<code>chr</code> や <code>printf</code> を生成する部分は長くなるので省いた。 </p> <pre class="highlight monospaced"><code>${ @@ -697,7 +697,7 @@ ${ '}</code></pre> <p> - は変数で、中にはスペースとエスケープが入っている (<code>chr(32) . chr(92)</code>)。シェルに渡されている文字列は次のようになる。 + は変数で、中にはスペースとエスケープが入っている (<code>chr(32) . chr(92)</code>)。シェルに渡されている文字列は次のようになる。 </p> <pre class="highlight monospaced"><code>e\ @@ -710,15 +710,15 @@ o\ 3\</code></pre> <p> - これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう (試してないけど)。 + これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう (試してないけど)。 </p> <p> - ということでこれは別解ということにしておく。 + ということでこれは別解ということにしておく。 </p> <p> - ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。 + ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。 </p> <pre class="highlight monospaced"><code>${ @@ -726,7 +726,7 @@ o\ '}</code></pre> <p> - 最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。 + 最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。 </p> </section> </div> diff --git a/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html b/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html index 11aeaba..e6d48a1 100644 --- a/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html +++ b/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -56,40 +56,40 @@ </li> </ol> </section> - <section id="section--_はじめに"> - <h2><a href="#section--_はじめに">はじめに</a></h2> + <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> から、トークン問題を出題予定である。 + 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> + 昨年のトークン問題の記事はこちら: <a href="/posts/2022-04-09/phperkaigi-2022-tokens">PHPerKaigi 2022 トークン問題の解説</a> </p> <p> - すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。 + すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。 </p> <p> - 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。 + 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。 </p> </section> - <section id="section--_問題"> - <h2><a href="#section--_問題">問題</a></h2> + <section id="section--quiz"> + <h2><a href="#section--quiz">問題</a></h2> <p> - 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 + 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta"><?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">'No input.'</span>); + <span class="hljs-keyword">exit</span>(<span class="hljs-string">'No input.'</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">'Invalid input.'</span>); + <span class="hljs-keyword">exit</span>(<span class="hljs-string">'Invalid input.'</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>))); @@ -98,71 +98,71 @@ $π = <span class="hljs-title function_ invoke__">trim</span>($π); <span class="hljs-variable">$t</span> = <span class="hljs-variable">$m</span>[<span class="hljs-number">1</span>] ?? <span class="hljs-string">''</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">'056e831a4146bf123e8ea16613303d2e'</span>) { -<span class="hljs-keyword">echo</span> <span class="hljs-string">"Token: <span class="hljs-subst">{$t}</span>\n"</span>; + <span class="hljs-keyword">echo</span> <span class="hljs-string">"Token: <span class="hljs-subst">{$t}</span>\n"</span>; } <span class="hljs-keyword">else</span> { -<span class="hljs-keyword">echo</span> <span class="hljs-string">"Failed.\n"</span>; + <span class="hljs-keyword">echo</span> <span class="hljs-string">"Failed.\n"</span>; }</code></pre> </section> - <section id="section--_トークン入手方法"> - <h2><a href="#section--_トークン入手方法">トークン入手方法</a></h2> + <section id="section--how-to-obtain-token"> + <h2><a href="#section--how-to-obtain-token">トークン入手方法</a></h2> <p> - ソースを見るとわかるとおり、<code>$argv[1]</code> を参照している。それを <code>$π</code> なる変数に代入しているので、円周率を渡してみる。 + ソースを見るとわかるとおり、<code>$argv[1]</code> を参照している。それを <code>$π</code> なる変数に代入しているので、円周率を渡してみる。 </p> <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ php Q.php 3.14 - Failed.</code></pre> +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 桁目まで入力したときで、こうなる。 + 最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。 </p> <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ php Q.php 3.1415926535897932 Token: #YO</code></pre> <p> - めでたくトークン「#YO」が手に入った。 + めでたくトークン「<code>#YO</code>」が手に入った。 </p> </section> - <section id="section--_解説"> - <h2><a href="#section--_解説">解説</a></h2> + <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">if</span> ($π === <span class="hljs-literal">null</span>) { <span class="hljs-keyword">exit</span>(<span class="hljs-string">'No input.'</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-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">'Invalid input.'</span>); - }</code></pre> +}</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>) している。 + <code>$π</code> を 2 文字ごとに区切り (<code>str_split</code>)、数値を ASCII コードと見做して文字に変換 (<code>chr</code>) して結合 (<code>implode</code>) している。 </p> <p> - 例えば、<code>$π</code> が <code>'656667'</code> だったとすると、<code>65</code>、<code>66</code>、<code>67</code> に対応した <code>'A'</code>、<code>'B'</code>、<code>'C'</code> へと変換され、<code>'ABC'</code> になる。 + 例えば、<code>$π</code> が <code>'656667'</code> だったとすると、<code>65</code>、<code>66</code>、<code>67</code> に対応した <code>'A'</code>、<code>'B'</code>、<code>'C'</code> へと変換され、<code>'ABC'</code> になる。 </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">$π = <span class="hljs-string">'656667'</span>; @@ -174,32 +174,32 @@ Token: #YO</code></pre> <span class="hljs-variable">$t</span> = <span class="hljs-variable">$m</span>[<span class="hljs-number">1</span>] ?? <span class="hljs-string">''</span>;</code></pre> <p> - 正規表現でマッチングしている。<code>\x23</code> は <code>#</code> と同じであることに留意すると、この正規表現は「<code>#</code> から始まる 2 以上の長さ (含 <code>#</code>) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。 + 正規表現でマッチングしている。<code>\x23</code> は <code>#</code> と同じであることに留意すると、この正規表現は「<code>#</code> から始まる 2 以上の長さ (含 <code>#</code>) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。 </p> <p> - なお、<code>#</code> を直接書いていないのは、<code>/#.+?) /</code> と書くと、<code>#.+?)</code> という意図せぬトークンが登録されてしまうからである。 + なお、<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">'056e831a4146bf123e8ea16613303d2e'</span>) { -<span class="hljs-keyword">echo</span> <span class="hljs-string">"Token: <span class="hljs-subst">{$t}</span>\n"</span>; + <span class="hljs-keyword">echo</span> <span class="hljs-string">"Token: <span class="hljs-subst">{$t}</span>\n"</span>; } <span class="hljs-keyword">else</span> { -<span class="hljs-keyword">echo</span> <span class="hljs-string">"Failed.\n"</span>; + <span class="hljs-keyword">echo</span> <span class="hljs-string">"Failed.\n"</span>; }</code></pre> <p> - 最後にトークンのハッシュ値を見て、想定解かどうかを確認する。 + 最後にトークンのハッシュ値を見て、想定解かどうかを確認する。 </p> </section> - <section id="section--_おわりに"> - <h2><a href="#section--_おわりに">おわりに</a></h2> + <section id="section--outro"> + <h2><a href="#section--outro">おわりに</a></h2> <p> - 円周率を何桁も計算して ASCII コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。 + 円周率を何桁も計算して ASCII コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。 </p> <p> - 最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた (ちなみに、それでも <code>M_PI</code> や <code>pi()</code> では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。 + 最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた (ちなみに、それでも <code>M_PI</code> や <code>pi()</code> では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。 </p> </section> </div> diff --git a/public/posts/2022-10-28/setup-server-for-this-site/index.html b/public/posts/2022-10-28/setup-server-for-this-site/index.html index ae78d67..63990bd 100644 --- a/public/posts/2022-10-28/setup-server-for-this-site/index.html +++ b/public/posts/2022-10-28/setup-server-for-this-site/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -53,106 +53,106 @@ </li> </ol> </section> - <section id="section--_はじめに"> - <h2><a href="#section--_はじめに">はじめに</a></h2> + <section id="section--intro"> + <h2><a href="#section--intro">はじめに</a></h2> <p> - これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS に移行した。そのときにおこなったサーバのセットアップ作業を書き残しておく。99 % 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。 + これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS に移行した。 そのときにおこなったサーバのセットアップ作業を書き残しておく。 99 % 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。 </p> <p> - 未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。 + 未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。 </p> </section> - <section id="section--_vps"> - <h2><a href="#section--_vps">VPS</a></h2> + <section id="section--vps"> + <h2><a href="#section--vps">VPS</a></h2> <p> - <a href="https://vps.sakura.ad.jp/">さくらの VPS</a> の 2 GB プラン。そこまで真面目に選定していないので、困ったら移動するかも。 + <a href="https://vps.sakura.ad.jp/">さくらの VPS</a> の 2 GB プラン。 そこまで真面目に選定していないので、困ったら移動するかも。 </p> </section> - <section id="section--_事前準備"> - <h2><a href="#section--_事前準備">事前準備</a></h2> - <section id="section--_サーバのホスト名を決める"> - <h3><a href="#section--_サーバのホスト名を決める">サーバのホスト名を決める</a></h3> + <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> - モチベーションが上がるという効能がある。今回は藤原定家から取って ``teika'' にした。たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。 + モチベーションが上がるという効能がある。今回は藤原定家から取って <code>teika</code> にした。 たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。 </p> </section> - <section id="section--_ssh_の鍵生成"> - <h3><a href="#section--_ssh_の鍵生成">SSH の鍵生成</a></h3> + <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> +$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key</code></pre> <p> - <code>teika.key</code> はローカルからサーバへの接続用、<code>github2teika.key</code> は、GitHub Actions からサーバへのデプロイ用。 + <code>teika.key</code> はローカルからサーバへの接続用、<code>github2teika.key</code> は、GitHub Actions からサーバへのデプロイ用。 </p> </section> - <section id="section--_ssh_の設定"> - <h3><a href="#section--_ssh_の設定">SSH の設定</a></h3> + <section id="section--preparation--ssh-config"> + <h3><a href="#section--preparation--ssh-config">SSH の設定</a></h3> <p> - <code>.ssh/config</code> に設定しておく。 + <code>.ssh/config</code> に設定しておく。 </p> <pre class="highlight" language="ssh_config" linenumbering="unnumbered"><code>Host teika - HostName ********** - User ********** - Port ********** - IdentityFile ~/.ssh/teika.key</code></pre> +HostName ********** +User ********** +Port ********** +IdentityFile ~/.ssh/teika.key</code></pre> </section> </section> - <section id="section--_基本のセットアップ"> - <h2><a href="#section--_基本のセットアップ">基本のセットアップ</a></h2> - <section id="section--_ssh_接続"> - <h3><a href="#section--_ssh_接続">SSH 接続</a></h3> + <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 契約時に設定した管理者ユーザとパスワードを使ってログインする。 + VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。 </p> </section> - <section id="section--_ユーザを作成する"> - <h3><a href="#section--_ユーザを作成する">ユーザを作成する</a></h3> + <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> で切り替え。 + 管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。<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> +$ sudo adduser ********** sudo +$ su ********** +$ cd</code></pre> </section> - <section id="section--_ホスト名を変える"> - <h3><a href="#section--_ホスト名を変える">ホスト名を変える</a></h3> + <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--_公開鍵を置く"> - <h3><a href="#section--_公開鍵を置く">公開鍵を置く</a></h3> + <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> +$ 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> の内容をコピーする。 + <code>authorized_keys</code> には、ローカルで生成した <code>~/.ssh/teika.key.pub</code> と <code>~/.ssh/github2teika.key.pub</code> の内容をコピーする。 </p> </section> - <section id="section--_ssh_の設定_2"> - <h3><a href="#section--_ssh_の設定_2">SSH の設定</a></h3> + <section id="section--basic-setup--ssh-config"> + <h3><a href="#section--basic-setup--ssh-config">SSH の設定</a></h3> <p> - SSH の設定を変更し、少しでも安全にしておく。 + 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> +$ sudo vi /etc/ssh/sshd_config</code></pre> <ul> <li> @@ -169,56 +169,56 @@ </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--_ssh_で接続確認"> - <h3><a href="#section--_ssh_で接続確認">SSH で接続確認</a></h3> + <section id="section--basic-setup--ssh-connect"> + <h3><a href="#section--basic-setup--ssh-connect">SSH で接続確認</a></h3> <p> - 今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。 + 今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。 </p> <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ ssh teika</code></pre> </section> - <section id="section--_ポートの遮断"> - <h3><a href="#section--_ポートの遮断">ポートの遮断</a></h3> + <section id="section--basic-setup--close-ports"> + <h3><a href="#section--basic-setup--close-ports">ポートの遮断</a></h3> <p> - デフォルトの 22 番を閉じ、設定したポートだけ空ける。 + デフォルトの 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> +$ sudo ufw allow ******* +$ sudo ufw enable +$ sudo ufw reload +$ sudo ufw status</code></pre> <p> - ここでもう一度 SSH の接続確認を挟む。 + ここでもう一度 SSH の接続確認を挟む。 </p> </section> - <section id="section--_github_用の_ssh_鍵"> - <h3><a href="#section--_github_用の_ssh_鍵">GitHub 用の SSH 鍵</a></h3> + <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 鍵を生成して置いておく。 + 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> から、この公開鍵を追加する。 + <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 @@ -227,77 +227,77 @@ User git IdentityFile ~/.ssh/github.key</code></pre> <p> - 最後に接続できるか確認しておく。 + 最後に接続できるか確認しておく。 </p> <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>ssh -T github.com</code></pre> </section> - <section id="section--_パッケージの更新"> - <h3><a href="#section--_パッケージの更新">パッケージの更新</a></h3> + <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> +$ sudo apt upgrade +$ sudo apt update +$ sudo apt upgrade +$ sudo apt autoremove</code></pre> </section> </section> - <section id="section--_サイトホスティング用のセットアップ"> - <h2><a href="#section--_サイトホスティング用のセットアップ">サイトホスティング用のセットアップ</a></h2> - <section id="section--_dns_に_ip_アドレスを登録する"> - <h3><a href="#section--_dns_に_ip_アドレスを登録する">DNS に IP アドレスを登録する</a></h3> + <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> レコードに直接入れるだけで済んだ。 + このサーバは固定の IP アドレスがあるので、<code>A</code> レコードに直接入れるだけで済んだ。 </p> </section> - <section id="section--_使うソフトウェアのインストール"> - <h3><a href="#section--_使うソフトウェアのインストール">使うソフトウェアのインストール</a></h3> + <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--_メインユーザが_docker_を使えるように"> - <h3><a href="#section--_メインユーザが_docker_を使えるように">メインユーザが Docker を使えるように</a></h3> + <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--_httphttps_を通す"> - <h3><a href="#section--_httphttps_を通す">HTTP/HTTPS を通す</a></h3> + <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 番を空ける。 + 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> +$ sudo ufw allow 443/tcp +$ sudo ufw reload +$ sudo ufw status</code></pre> </section> - <section id="section--_リポジトリのクローン"> - <h3><a href="#section--_リポジトリのクローン">リポジトリのクローン</a></h3> + <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> +$ git clone git@github.com:nsfisis/nsfisis.dev.git +$ cd nsfisis.dev +$ git submodule update --init</code></pre> </section> - <section id="section--_certbot_で証明書取得"> - <h3><a href="#section--_certbot_で証明書取得">certbot で証明書取得</a></h3> + <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> +$ make setup</code></pre> </section> - <section id="section--_サーバを稼動させる"> - <h3><a href="#section--_サーバを稼動させる">サーバを稼動させる</a></h3> + <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--_感想"> - <h2><a href="#section--_感想">感想</a></h2> + <section id="section--outro"> + <h2><a href="#section--outro">感想</a></h2> <p> - (業務でなく) 個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。 + (業務でなく) 個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。 </p> </section> </div> diff --git a/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html b/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html index 57cb255..09a9f84 100644 --- a/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html +++ b/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -56,78 +56,73 @@ </li> </ol> </section> - <section id="section--_はじめに"> - <h2><a href="#section--_はじめに">はじめに</a></h2> + <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> からトークン問題を出題予定である。 + 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> + 昨年のトークン問題の記事はこちら: <a href="/posts/2022-04-09/phperkaigi-2022-tokens/">PHPerKaigi 2022 トークン問題の解説</a> </p> <p> - すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。 + すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。 </p> <p> - 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。 + 10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。 </p> <p> - その 1 はこちら: <a href="/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/">PHPerKaigi 2023: ボツになったトークン問題 その 1</a> + その 1 はこちら: <a href="/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/">PHPerKaigi 2023: ボツになったトークン問題 その 1</a> </p> </section> - <section id="section--_問題"> - <h2><a href="#section--_問題">問題</a></h2> + <section id="section--quiz"> + <h2><a href="#section--quiz">問題</a></h2> <p> - 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 + 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - </code></pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span></code></pre> <p> - "And Then There Were None" (そして誰もいなくなった) と名付けた作品。変則 quine (自分自身と同じソースコードを出力するプログラム) になっている。 + "And Then There Were None" (そして誰もいなくなった) と名付けた作品。変則 quine (自分自身と同じソースコードを出力するプログラム) になっている。 </p> </section> - <section id="section--_トークン入手方法"> - <h2><a href="#section--_トークン入手方法">トークン入手方法</a></h2> + <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"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - </code></pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment">#</span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span></code></pre> <p> - 1 行目を除き、先ほどのコードとほぼ同じものが出てきた。もう一度実行してみる。 + 1 行目を除き、先ほどのコードとほぼ同じものが出てきた。もう一度実行してみる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"> - <span class="hljs-comment">#</span> + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-comment">#</span> W <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> @@ -136,47 +131,42 @@ W <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> -</code></pre> +<span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">""</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span></code></pre> <p> - 今度は 2 行目が書き換えられた。すべての行が変化するまで繰り返すと次のようになる。 + 今度は 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> + <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」が手に入った。 + トークン「#WELOVEPHP」が手に入った。 </p> </section> - <section id="section--_解説"> - <h2><a href="#section--_解説">解説</a></h2> + <section id="section--commentary"> + <h2><a href="#section--commentary">解説</a></h2> <p> - 一見すると同じ行が 10 行並んでいるだけなのにも関わらず、なぜそれぞれの行で出力が変わるのか。ソースコードをコピーして、適当なエディタに貼り付けるとわかりやすい。 + 一見すると同じ行が 10 行並んでいるだけなのにも関わらず、なぜそれぞれの行で出力が変わるのか。ソースコードをコピーして、適当なエディタに貼り付けるとわかりやすい。 </p> <p> - Vim で開くと次のようになる (1 行目を抜粋)。 + Vim で開くと次のようになる (1 行目を抜粋)。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"> - <span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">"<200b>"</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span> - </code></pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-meta"><?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>)=></span><span class="hljs-title function_ invoke__">trim</span>(<span class="hljs-variable">$s</span>,<span class="hljs-string">"<200b>"</span>):<span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$s</span></span>)=></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">'<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span>).<span class="hljs-string">"\n"</span>,<span class="hljs-string">"\x27<span class="hljs-subst">$s</span>\x27"</span>);<span class="hljs-meta">?></span></code></pre> <p> - <code><200b></code> と表示されているのは、Unicode の U+200b で、ゼロ幅スペースである。 + <code><200b></code> と表示されているのは、Unicode の U+200b で、ゼロ幅スペースである。 </p> <div> @@ -185,48 +175,44 @@ W </div> <div> <p> - エディタによっては、ゼロ幅スペースが見えないことがある。VSCode ではブラウザと同様に不可視だった。 + エディタによっては、ゼロ幅スペースが見えないことがある。VSCode ではブラウザと同様に不可視だった。 </p> </div> </div> <p> - 文字列リテラルの中にゼロ幅スペースを仕込むことで、見た目を変えずに情報をエンコードすることが可能となる。 + 文字列リテラルの中にゼロ幅スペースを仕込むことで、見た目を変えずに情報をエンコードすることが可能となる。 </p> <p> - 続いて、トークンへの変換ロジックを解析する。注目すべきはこの部分だ。以下、ゼロ幅スペースは Vim での表示に合わせて <code><200b></code> と記載する。 + 続いて、トークンへの変換ロジックを解析する。注目すべきはこの部分だ。以下、ゼロ幅スペースは Vim での表示に合わせて <code><200b></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>)=></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> + <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>)=></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> は以下の内容となっており、 + 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">'<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span> - </code></pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$s</span>=<span class="hljs-string">'<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span></code></pre> <p> - このソースコードは UTF-8 で書かれているので、105 バイトになる。それを 3 で割ると 35 となり、これは <code>#</code> の ASCII コードと一致する。他の行も、同様にしてゼロ幅スペースを詰めることで文字列長を調整し、トークンをエンコードしている。 + このソースコードは UTF-8 で書かれているので、105 バイトになる。それを 3 で割ると 35 となり、これは <code>#</code> の ASCII コードと一致する。他の行も、同様にしてゼロ幅スペースを詰めることで文字列長を調整し、トークンをエンコードしている。 </p> <p> - デコード部以外の部分は、quine のための記述である。 + デコード部以外の部分は、quine のための記述である。 </p> </section> - <section id="section--_おわりに"> - <h2><a href="#section--_おわりに">おわりに</a></h2> + <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 にもするとこうなった。 + <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> diff --git a/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html b/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html index 19b947b..1c73981 100644 --- a/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html +++ b/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> @@ -213,17 +213,17 @@ </p> </section> - <section id="section--_解説"> - <h2><a href="#section--_解説">解説</a></h2> - <section id="section--_概要"> - <h3><a href="#section--_概要">概要</a></h3> + <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--_例外オブジェクトの連鎖"> - <h3><a href="#section--_例外オブジェクトの連鎖">例外オブジェクトの連鎖</a></h3> + <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> @@ -262,8 +262,8 @@ </p> </section> - <section id="section--_出力部の解析"> - <h3><a href="#section--_出力部の解析">出力部の解析</a></h3> + <section id="section--commentary--output"> + <h3><a href="#section--commentary--output">出力部の解析</a></h3> <p> 出力部をコメントや改行を追加して再掲する: </p> @@ -297,8 +297,8 @@ </p> </section> - <section id="section--_データ構成部の解析"> - <h3><a href="#section--_データ構成部の解析">データ構成部の解析</a></h3> + <section id="section--commentary--data-construction"> + <h3><a href="#section--commentary--data-construction">データ構成部の解析</a></h3> <p> <code>f()</code> の定義を再掲する (エラーオブジェクトの行数を利用しているので、一部分だけ抜き出すと値が変わることに注意): </p> diff --git a/public/posts/2023-03-10/rewrite-this-blog-generator/index.html b/public/posts/2023-03-10/rewrite-this-blog-generator/index.html index 018314c..bc4c992 100644 --- a/public/posts/2023-03-10/rewrite-this-blog-generator/index.html +++ b/public/posts/2023-03-10/rewrite-this-blog-generator/index.html @@ -8,7 +8,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> diff --git a/public/posts/index.html b/public/posts/index.html index fa3c6b7..75fd8d3 100644 --- a/public/posts/index.html +++ b/public/posts/index.html @@ -8,7 +8,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/slides/2023-01-18/phpstudy-tokyo-148/index.html b/public/slides/2023-01-18/phpstudy-tokyo-148/index.html index df84fd0..b5ad0af 100644 --- a/public/slides/2023-01-18/phpstudy-tokyo-148/index.html +++ b/public/slides/2023-01-18/phpstudy-tokyo-148/index.html @@ -9,7 +9,7 @@ <meta name="keywords" content="PHP,PHP 勉強会@東京"> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <title>PHP 勉強会@東京 第148 回 (LT) | REPL: Rest-Eat-Program Loop</title> - <link rel="stylesheet" href="/style.css?h=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> diff --git a/public/slides/2023-02-15/phpstudy-tokyo-149/index.html b/public/slides/2023-02-15/phpstudy-tokyo-149/index.html index 1bce7a6..a437dd9 100644 --- a/public/slides/2023-02-15/phpstudy-tokyo-149/index.html +++ b/public/slides/2023-02-15/phpstudy-tokyo-149/index.html @@ -9,7 +9,7 @@ <meta name="keywords" content="PHP,PHP 勉強会@東京"> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <title>PHP 勉強会@東京 第149 回 (LT) | REPL: Rest-Eat-Program Loop</title> - <link rel="stylesheet" href="/style.css?h=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> diff --git a/public/slides/2023-03-15/phpstudy-tokyo-150/index.html b/public/slides/2023-03-15/phpstudy-tokyo-150/index.html index 91e35ef..c8667e2 100644 --- a/public/slides/2023-03-15/phpstudy-tokyo-150/index.html +++ b/public/slides/2023-03-15/phpstudy-tokyo-150/index.html @@ -9,7 +9,7 @@ <meta name="keywords" content="PHP,PHP 勉強会@東京"> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <title>PHP 勉強会@東京 第150 回 (LT) | REPL: Rest-Eat-Program Loop</title> - <link rel="stylesheet" href="/style.css?h=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> diff --git a/public/slides/2023-03-24/phperkaigi-2023/index.html b/public/slides/2023-03-24/phperkaigi-2023/index.html index a07c224..9bcaf69 100644 --- a/public/slides/2023-03-24/phperkaigi-2023/index.html +++ b/public/slides/2023-03-24/phperkaigi-2023/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> diff --git a/public/slides/index.html b/public/slides/index.html index 614cd46..79d76f9 100644 --- a/public/slides/index.html +++ b/public/slides/index.html @@ -8,7 +8,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/style.css b/public/style.css index 2376133..191c57e 100644 --- a/public/style.css +++ b/public/style.css @@ -125,6 +125,10 @@ code { border-radius: 2px; } +pre code { + padding: 0; +} + li.revision { list-style: inside; } diff --git a/public/tags/conference/index.html b/public/tags/conference/index.html index 1e8f3b9..1521ce9 100644 --- a/public/tags/conference/index.html +++ b/public/tags/conference/index.html @@ -9,7 +9,7 @@ <meta name="keywords" 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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/cpp/index.html b/public/tags/cpp/index.html index 8aee4aa..5d766d7 100644 --- a/public/tags/cpp/index.html +++ b/public/tags/cpp/index.html @@ -9,7 +9,7 @@ <meta name="keywords" content="C++"> <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/cpp17/index.html b/public/tags/cpp17/index.html index 867a02a..e9d0dc2 100644 --- a/public/tags/cpp17/index.html +++ b/public/tags/cpp17/index.html @@ -9,7 +9,7 @@ <meta name="keywords" content="C++ 17"> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <title>タグ「C++ 17」一覧 | REPL: Rest-Eat-Program Loop</title> - <link rel="stylesheet" href="/style.css?h=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/index.html b/public/tags/index.html index de56df1..50ad5fd 100644 --- a/public/tags/index.html +++ b/public/tags/index.html @@ -8,7 +8,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/note-to-self/index.html b/public/tags/note-to-self/index.html index 02626ac..c305137 100644 --- a/public/tags/note-to-self/index.html +++ b/public/tags/note-to-self/index.html @@ -9,7 +9,7 @@ <meta name="keywords" 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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/php/index.html b/public/tags/php/index.html index 94a555f..7409968 100644 --- a/public/tags/php/index.html +++ b/public/tags/php/index.html @@ -9,7 +9,7 @@ <meta name="keywords" content="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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/phpcon/index.html b/public/tags/phpcon/index.html index 3c682f8..cfa9588 100644 --- a/public/tags/phpcon/index.html +++ b/public/tags/phpcon/index.html @@ -9,7 +9,7 @@ <meta name="keywords" content="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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/phperkaigi/index.html b/public/tags/phperkaigi/index.html index 47faf40..3a73be3 100644 --- a/public/tags/phperkaigi/index.html +++ b/public/tags/phperkaigi/index.html @@ -9,7 +9,7 @@ <meta name="keywords" content="PHPerKaigi"> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <title>タグ「PHPerKaigi」一覧 | REPL: Rest-Eat-Program Loop</title> - <link rel="stylesheet" href="/style.css?h=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/phpstudy-tokyo/index.html b/public/tags/phpstudy-tokyo/index.html index 2890115..8feb838 100644 --- a/public/tags/phpstudy-tokyo/index.html +++ b/public/tags/phpstudy-tokyo/index.html @@ -9,7 +9,7 @@ <meta name="keywords" content="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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/python/index.html b/public/tags/python/index.html index bcc5e70..60559e3 100644 --- a/public/tags/python/index.html +++ b/public/tags/python/index.html @@ -9,7 +9,7 @@ <meta name="keywords" content="Python"> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <title>タグ「Python」一覧 | REPL: Rest-Eat-Program Loop</title> - <link rel="stylesheet" href="/style.css?h=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/python3/index.html b/public/tags/python3/index.html index c8e69b8..9c7eb59 100644 --- a/public/tags/python3/index.html +++ b/public/tags/python3/index.html @@ -9,7 +9,7 @@ <meta name="keywords" content="Python 3"> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <title>タグ「Python 3」一覧 | REPL: Rest-Eat-Program Loop</title> - <link rel="stylesheet" href="/style.css?h=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/ruby/index.html b/public/tags/ruby/index.html index 912edef..e7364a3 100644 --- a/public/tags/ruby/index.html +++ b/public/tags/ruby/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/ruby3/index.html b/public/tags/ruby3/index.html index b79ffd6..8eef911 100644 --- a/public/tags/ruby3/index.html +++ b/public/tags/ruby3/index.html @@ -9,7 +9,7 @@ <meta name="keywords" content="Ruby 3"> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <title>タグ「Ruby 3」一覧 | REPL: Rest-Eat-Program Loop</title> - <link rel="stylesheet" href="/style.css?h=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/rust/index.html b/public/tags/rust/index.html index af1fa0f..49476db 100644 --- a/public/tags/rust/index.html +++ b/public/tags/rust/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/public/tags/vim/index.html b/public/tags/vim/index.html index dfe9b16..f047bb7 100644 --- a/public/tags/vim/index.html +++ b/public/tags/vim/index.html @@ -9,7 +9,7 @@ <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=48694677b43b77e5c45f25e6bfdebb41"> + <link rel="stylesheet" href="/style.css?h=36f8a090080ebb76d78b17f1d93b3ba4"> </head> <body class="list"> <header class="header"> diff --git a/static/style.css b/static/style.css index 2376133..191c57e 100644 --- a/static/style.css +++ b/static/style.css @@ -125,6 +125,10 @@ code { border-radius: 2px; } +pre code { + padding: 0; +} + li.revision { list-style: inside; } |
