diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-04-02 00:11:46 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-04-02 00:11:46 +0900 |
| commit | c0c73379890f1a4ee6ee07b1aee188c33ef66ab0 (patch) | |
| tree | 62ad848a658fa0dc8a43bc106e05aadcd4a70b8f | |
| parent | f325479ddb8ccdbe0e832160e9c7fb0155a90f47 (diff) | |
| download | nsfisis.dev-c0c73379890f1a4ee6ee07b1aee188c33ef66ab0.tar.gz nsfisis.dev-c0c73379890f1a4ee6ee07b1aee188c33ef66ab0.tar.zst nsfisis.dev-c0c73379890f1a4ee6ee07b1aee188c33ef66ab0.zip | |
feat(blog/nuldoc): dynamically join nested section ids
22 files changed, 151 insertions, 119 deletions
diff --git a/vhosts/blog/content/posts/2021-03-30/phperkaigi-2021.ndoc b/vhosts/blog/content/posts/2021-03-30/phperkaigi-2021.ndoc index 2dd50bae..9589e49b 100644 --- a/vhosts/blog/content/posts/2021-03-30/phperkaigi-2021.ndoc +++ b/vhosts/blog/content/posts/2021-03-30/phperkaigi-2021.ndoc @@ -31,7 +31,7 @@ remark = "公開" 発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。 </p> - <section id="report-legend"> + <section id="legend"> <h>凡例</h> <blockquote> <p> @@ -42,9 +42,9 @@ remark = "公開" 感想など </p> </section> - <section id="report--day-0"> + <section id="day-0"> <h>Day 0 前夜祭 (2021/03/27)</h> - <section id="report--day-0--1730-a"> + <section id="1730-a"> <h>17:30 [A]</h> <p> PHP で AWS Lambda @@ -100,7 +100,7 @@ remark = "公開" だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。 </p> </section> - <section id="report--day-0--1810-a"> + <section id="1810-a"> <h>18:10 [A]</h> <p> 大規模サイトの SEO @@ -152,7 +152,7 @@ remark = "公開" は大して知らないので新鮮な話が多かった。その分語れることも少ない……。 </p> </section> - <section id="report--day-0--1850-a"> + <section id="1850-a"> <h>18:50 [A]</h> <blockquote> <p> @@ -214,7 +214,7 @@ remark = "公開" いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。 </p> </section> - <section id="report--day-0--1930-a"> + <section id="1930-a"> <h>19:30 [A]</h> <p> PHP で FUSE @@ -281,9 +281,9 @@ remark = "公開" </p> </section> </section> - <section id="report--day-1"> + <section id="day-1"> <h>Day 1 (2021/03/27)</h> - <section id="report--day-1--1050-a"> + <section id="1050-a"> <h>10:50 [A]</h> <p> ATDD @@ -377,7 +377,7 @@ remark = "公開" 高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。 </p> </section> - <section id="report--day-1--1150-a"> + <section id="1150-a"> <h>11:50 [A]</h> <p> 型解析を用いたリファクタリング @@ -418,13 +418,13 @@ remark = "公開" Ruby の typeprof には注目している。 </p> </section> - <section id="report--day-1--1230-a"> + <section id="1230-a"> <h>12:30 [A]</h> <p> 昼食をとっていた。事前に何か食料を買っておくべきだった。 </p> </section> - <section id="report--day-1--1310-a"> + <section id="1310-a"> <h>13:10 [A]</h> <p> Documentation as Code @@ -487,7 +487,7 @@ remark = "公開" 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。 </p> </section> - <section id="report--day-1--1410-a"> + <section id="1410-a"> <h>14:10 [A]</h> <p> cookie による session 管理 @@ -497,7 +497,7 @@ remark = "公開" やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。 </p> </section> - <section id="report--day-1--1450-a"> + <section id="1450-a"> <h>14:50 [A]</h> <p> PHP のエラーと例外 @@ -610,7 +610,7 @@ remark = "公開" のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。 </p> </section> - <section id="report--day-1--1530-a"> + <section id="1530-a"> <h>15:30 [A]</h> <p> Laravel のメール認証 @@ -620,7 +620,7 @@ remark = "公開" の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。 </p> </section> - <section id="report--day-1--1610-a"> + <section id="1610-a"> <h>16:10 [A]</h> <p> gRPC @@ -674,7 +674,7 @@ remark = "公開" というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。 </p> </section> - <section id="report--day-1--1650-a"> + <section id="1650-a"> <h>16:50 [A]</h> <p> アーキテクチャテスト @@ -723,7 +723,7 @@ remark = "公開" </blockquote> </section> </section> - <section id="report--day-2"> + <section id="day-2"> <h>Day 2 (2021/03/28)</h> <p> 冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。 @@ -732,7 +732,7 @@ remark = "公開" 残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。 </p> </section> - <section id="report--comments"> + <section id="comments"> <h>全体の感想</h> <p> Day 2 diff --git a/vhosts/blog/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.ndoc b/vhosts/blog/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.ndoc index 44713acd..705cf6c4 100644 --- a/vhosts/blog/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.ndoc +++ b/vhosts/blog/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.ndoc @@ -54,7 +54,7 @@ remark = "Qiita から移植" <a href="https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3">neovim (上に同じ)</a> </p> </blockquote> - <section id="code-reading--vim"> + <section id="vim"> <h>vim のソースコード</h> <p> 以下は、autocmd events @@ -90,7 +90,7 @@ remark = "Qiita から移植" ]]> </codeblock> </section> - <section id="code-reading--neovim"> + <section id="neovim"> <h>neovim のソースコード</h> <p> neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua diff --git a/vhosts/blog/content/posts/2021-10-02/vim-swap-order-of-selected-lines.ndoc b/vhosts/blog/content/posts/2021-10-02/vim-swap-order-of-selected-lines.ndoc index 699a0e28..149d038d 100644 --- a/vhosts/blog/content/posts/2021-10-02/vim-swap-order-of-selected-lines.ndoc +++ b/vhosts/blog/content/posts/2021-10-02/vim-swap-order-of-selected-lines.ndoc @@ -42,7 +42,7 @@ remark = "Qiita から移植" </section> <section id="existing-solution"> <h>よく紹介されている手法</h> - <section id="existing-solution--external-commands"> + <section id="external-commands"> <h><code>tac</code> / <code>tail</code></h> <p> <code>tac</code> や <code>tail -r</code> などの外部コマンドを <code>!</code> @@ -58,7 +58,7 @@ remark = "Qiita から移植" オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい </p> </section> - <section id="existing-solution--global-command"> + <section id="global-command"> <h><code>:g/^/m0</code></h> <p> こちらは外部コマンドに頼らず、Vim の機能のみを使う。<code>g</code> は <code>:global</code> diff --git a/vhosts/blog/content/posts/2022-04-09/phperkaigi-2022-tokens.ndoc b/vhosts/blog/content/posts/2022-04-09/phperkaigi-2022-tokens.ndoc index 68ef7dd2..c0540482 100644 --- a/vhosts/blog/content/posts/2022-04-09/phperkaigi-2022-tokens.ndoc +++ b/vhosts/blog/content/posts/2022-04-09/phperkaigi-2022-tokens.ndoc @@ -111,16 +111,16 @@ remark = "2問目、3問目の解説を追加、1問目に加筆" <p> この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。 </p> - <section id="q1-brainfuck--commentary"> + <section id="commentary"> <h>解説</h> - <section id="q1-brainfuck--commentary--emoji"> + <section id="emoji"> <h>絵文字</h> <p> まず目につくのは大量の絵文字だろう。 PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。 </p> </section> - <section id="q1-brainfuck--commentary--brainfuck"> + <section id="brainfuck"> <h>プログラム全体</h> <p> Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck @@ -182,7 +182,7 @@ remark = "2問目、3問目の解説を追加、1問目に加筆" なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。 </p> </section> - <section id="q1-brainfuck--commentary--emoji-selection"> + <section id="emoji-selection"> <h>絵文字の選択</h> <p> おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> @@ -190,7 +190,7 @@ remark = "2問目、3問目の解説を追加、1問目に加筆" のマスコットの象に由来する。 </p> </section> - <section id="q1-brainfuck--commentary--strict-types"> + <section id="strict-types"> <h>strict_types</h> <p> <code>declare</code> 文の <code>strict_types</code> に指定できるのは、<code>0</code> か <code>1</code> @@ -198,7 +198,7 @@ remark = "2問目、3問目の解説を追加、1問目に加筆" 8.1 から追加された、<code>0O</code> または <code>0o</code> から始まる八進数リテラルを使った。 </p> </section> - <section id="q1-brainfuck--commentary--url"> + <section id="url"> <h>URL</h> <p> ソースコードのライセンスを示したこの部分だが、 @@ -213,7 +213,7 @@ remark = "2問目、3問目の解説を追加、1問目に加筆" 以降は行コメントになっている。 </p> </section> - <section id="q1-brainfuck--commentary--numbers"> + <section id="numbers"> <h>リテラルなしで数値を生成する</h> <p> ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 @@ -242,7 +242,7 @@ remark = "2問目、3問目の解説を追加、1問目に加筆" にし、さらにビット反転して <code>-1</code> にしている。 </p> </section> - <section id="q1-brainfuck--commentary--conditionals"> + <section id="conditionals"> <h><code>if</code> 文なしで条件分岐</h> <p> 三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> @@ -251,7 +251,7 @@ remark = "2問目、3問目の解説を追加、1問目に加筆" のような形で分岐することもできる。 </p> </section> - <section id="q1-brainfuck--commentary--loops"> + <section id="loops"> <h><code>while</code>、<code>for</code> 文なしでループ</h> <p> 不動点コンビネータを使って無名再帰する @@ -321,7 +321,7 @@ remark = "2問目、3問目の解説を追加、1問目に加筆" <p> ここでは、私の想定解を解説する。 </p> - <section id="q2-riddle--code-reading"> + <section id="code-reading"> <h>読解</h> <p> まずはソースコードを読んでいく。 @@ -369,7 +369,7 @@ remark = "2問目、3問目の解説を追加、1問目に加筆" 5文字ごとに区切ったあと、改行で結合している。 </p> </section> - <section id="q2-riddle--hint"> + <section id="hint"> <h>ヒント</h> <p> 次に、ソースコードに書いてあるヒントを読んでいく。 @@ -387,7 +387,7 @@ remark = "2問目、3問目の解説を追加、1問目に加筆" ファイルに追加ヒントとして書かれている)。 </p> </section> - <section id="q2-riddle--solve"> + <section id="solve"> <h>解く</h> <p> ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> @@ -501,9 +501,9 @@ remark = "2問目、3問目の解説を追加、1問目に加筆" <p> 実際にはもう少しパイプで繋げなければならない。 </p> - <section id="q3-toquine--commentary"> + <section id="commentary"> <h>解説</h> - <section id="q3-toquine--commentary--quine"> + <section id="quine"> <h>プログラム全体</h> <p> コメントにもあるとおり、これは quine (風) のプログラムになっている。 @@ -515,14 +515,14 @@ remark = "2問目、3問目の解説を追加、1問目に加筆" 異なるのはトークンになっている部分のみである。 </p> </section> - <section id="q3-toquine--commentary--tokens"> + <section id="tokens"> <h>トークン</h> <p> <code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> とほぼ同じなので省略する。 </p> </section> - <section id="q3-toquine--commentary--states"> + <section id="states"> <h>状態保持</h> <p> トークンの何文字目まで出力したかを、ソースコードを変えずに (quine @@ -531,7 +531,7 @@ remark = "2問目、3問目の解説を追加、1問目に加筆" から情報を取得している。 </p> </section> - <section id="q3-toquine--commentary--rot-13"> + <section id="rot-13"> <h>ROT 13</h> <p> Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。 diff --git a/vhosts/blog/content/posts/2022-05-01/phperkaigi-2022.ndoc b/vhosts/blog/content/posts/2022-05-01/phperkaigi-2022.ndoc index a43a140c..28151668 100644 --- a/vhosts/blog/content/posts/2022-05-01/phperkaigi-2022.ndoc +++ b/vhosts/blog/content/posts/2022-05-01/phperkaigi-2022.ndoc @@ -28,7 +28,7 @@ remark = "公開" </section> <section id="comments"> <h>感想</h> - <section id="comments--great-sessions"> + <section id="great-sessions"> <h>厳選おすすめトーク</h> <p> 多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。 @@ -103,21 +103,21 @@ remark = "公開" </p> </blockquote> </section> - <section id="comments--token-quizzes"> + <section id="token-quizzes"> <h>トークン問題の作成</h> <p> 今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。 こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。 </p> </section> - <section id="comments--phper-challenge"> + <section id="phper-challenge"> <h>PHPer チャレンジ</h> <p> <a href="https://fortee.jp/phperkaigi-2022/challenge">1位</a>になった。<br/> また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a> をいただいた。 </p> </section> - <section id="comments--conference"> + <section id="conference"> <h>カンファレンス全体への感想</h> <p> <a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> では、こんなことを書いた。 diff --git a/vhosts/blog/content/posts/2022-08-27/php-conference-okinawa-code-golf.ndoc b/vhosts/blog/content/posts/2022-08-27/php-conference-okinawa-code-golf.ndoc index 062a8b02..056ac438 100644 --- a/vhosts/blog/content/posts/2022-08-27/php-conference-okinawa-code-golf.ndoc +++ b/vhosts/blog/content/posts/2022-08-27/php-conference-okinawa-code-golf.ndoc @@ -70,7 +70,7 @@ remark = "公開" </section> <section id="techniques"> <h>使用したテクニック</h> - <section id="techniques--exponential-notation"> + <section id="exponential-notation"> <h>指数表記</h> <p> 割と多くの言語のゴルフで使えるテクニック。 @@ -78,7 +78,7 @@ remark = "公開" このコードでは <code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。 </p> </section> - <section id="techniques--shorten-loop"> + <section id="shorten-loop"> <h>foreach や for の中身を1つの文に</h> <p> <code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、 @@ -86,7 +86,7 @@ remark = "公開" C言語などでも使える。 </p> </section> - <section id="techniques--omit-initialization"> + <section id="omit-initialization"> <h>$r に初期値を入れない</h> <p> PHP では、<code>$r[] = ......</code> のような配列の末尾に追加する式を実行したとき、 @@ -102,7 +102,7 @@ remark = "公開" もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。 </p> </section> - <section id="techniques--put-text-outside-php-tag"> + <section id="put-text-outside-php-tag"> <h>PHP タグの外に文字列を置く</h> <p> PHP では、<code><?php</code> <code>?></code> で囲われた部分の外側にある文字列は、そのまま出力される。 diff --git a/vhosts/blog/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.ndoc b/vhosts/blog/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.ndoc index 6a7d4a31..f8b0d62e 100644 --- a/vhosts/blog/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.ndoc +++ b/vhosts/blog/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.ndoc @@ -202,7 +202,7 @@ remark = "小さな文言の修正・変更" </section> <section id="commentary"> <h>解説</h> - <section id="commentary--normal-fizzbuzz"> + <section id="normal-fizzbuzz"> <h>普通の (?) fizzbuzz</h> <p> まずは普通に書くとしよう。 @@ -220,7 +220,7 @@ remark = "小さな文言の修正・変更" 素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。 </p> </section> - <section id="commentary--remove-keywords"> + <section id="remove-keywords"> <h><code>for</code> の排除</h> <p> <code>for</code> は、3文字もある長いキーワードである。 @@ -244,7 +244,7 @@ remark = "小さな文言の修正・変更" なお、<code>echo</code> は文 (statement) であり式 (expression) ではないので、式である <code>printf</code> に置き換えた。 </p> </section> - <section id="commentary--shorten-function-invocation"> + <section id="shorten-function-invocation"> <h>関数呼び出しの短縮</h> <p> <code>range</code>、<code>array_walk</code>、<code>printf</code> は長すぎるのでどうにかせねばならない。 @@ -273,7 +273,7 @@ remark = "小さな文言の修正・変更" 次のテクニックへ移ろう。 </p> </section> - <section id="commentary--incompatible-solution"> + <section id="incompatible-solution"> <h>余談: PHP 8.x で動作しなくてもいいなら</h> <p> 今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。 @@ -318,7 +318,7 @@ remark = "小さな文言の修正・変更" むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。 </p> </section> - <section id="commentary--shorten-string-literals"> + <section id="shorten-string-literals"> <h>文字列リテラルの短縮</h> <p> 実際に使った手法の説明に移る。 diff --git a/vhosts/blog/content/posts/2022-10-28/setup-server-for-this-site.ndoc b/vhosts/blog/content/posts/2022-10-28/setup-server-for-this-site.ndoc index a601b8b4..c10ad115 100644 --- a/vhosts/blog/content/posts/2022-10-28/setup-server-for-this-site.ndoc +++ b/vhosts/blog/content/posts/2022-10-28/setup-server-for-this-site.ndoc @@ -36,14 +36,14 @@ remark = "ssh_config に IdentitiesOnly yes を追加" </section> <section id="preparation"> <h>事前準備</h> - <section id="preparation--hostname"> + <section id="hostname"> <h>サーバのホスト名を決める</h> <p> モチベーションが上がるという効能がある。今回は藤原定家から取って <code>teika</code> にした。 たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。 </p> </section> - <section id="preparation--ssh-key"> + <section id="ssh-key"> <h>SSH の鍵生成</h> <p> ローカルマシンで鍵を生成する。 @@ -59,7 +59,7 @@ remark = "ssh_config に IdentitiesOnly yes を追加" GitHub Actions からサーバへのデプロイ用。 </p> </section> - <section id="preparation--ssh-config"> + <section id="ssh-config"> <h>SSH の設定</h> <p> <code>.ssh/config</code> に設定しておく。 @@ -78,13 +78,13 @@ remark = "ssh_config に IdentitiesOnly yes を追加" </section> <section id="basic-setup"> <h>基本のセットアップ</h> - <section id="basic-setup--login"> + <section id="login"> <h>SSH 接続</h> <p> VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。 </p> </section> - <section id="basic-setup--user"> + <section id="user"> <h>ユーザを作成する</h> <p> 管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。 @@ -99,7 +99,7 @@ remark = "ssh_config に IdentitiesOnly yes を追加" ]]> </codeblock> </section> - <section id="basic-setup--hostname"> + <section id="hostname"> <h>ホスト名を変える</h> <codeblock language="shell-session"> <![CDATA[ @@ -107,7 +107,7 @@ remark = "ssh_config に IdentitiesOnly yes を追加" ]]> </codeblock> </section> - <section id="basic-setup--public-key"> + <section id="public-key"> <h>公開鍵を置く</h> <codeblock language="shell-session"> <![CDATA[ @@ -121,7 +121,7 @@ remark = "ssh_config に IdentitiesOnly yes を追加" <code>~/.ssh/github2teika.key.pub</code> の内容をコピーする。 </p> </section> - <section id="basic-setup--ssh-config"> + <section id="ssh-config"> <h>SSH の設定</h> <p> SSH の設定を変更し、少しでも安全にしておく。 @@ -147,7 +147,7 @@ remark = "ssh_config に IdentitiesOnly yes を追加" ]]> </codeblock> </section> - <section id="basic-setup--ssh-connect"> + <section id="ssh-connect"> <h>SSH で接続確認</h> <p> 今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。 @@ -159,7 +159,7 @@ remark = "ssh_config に IdentitiesOnly yes を追加" ]]> </codeblock> </section> - <section id="basic-setup--close-ports"> + <section id="close-ports"> <h>ポートの遮断</h> <p> デフォルトの 22 番を閉じ、設定したポートだけ空ける。 @@ -177,7 +177,7 @@ remark = "ssh_config に IdentitiesOnly yes を追加" ここでもう一度 SSH の接続確認を挟む。 </p> </section> - <section id="basic-setup--ssh-key-for-github"> + <section id="ssh-key-for-github"> <h>GitHub 用の SSH 鍵</h> <p> GitHub に置いてある private リポジトリをサーバから clone したいので、SSH 鍵を生成して置いておく。 @@ -218,7 +218,7 @@ remark = "ssh_config に IdentitiesOnly yes を追加" ]]> </codeblock> </section> - <section id="basic-setup--upgrade-packages"> + <section id="upgrade-packages"> <h>パッケージの更新</h> <codeblock language="shell-session"> <![CDATA[ @@ -233,13 +233,13 @@ remark = "ssh_config に IdentitiesOnly yes を追加" </section> <section id="site-hosting-setup"> <h>サイトホスティング用のセットアップ</h> - <section id="site-hosting-setup--dns"> + <section id="dns"> <h>DNS に IP アドレスを登録する</h> <p> このサーバは固定の IP アドレスがあるので、<code>A</code> レコードに直接入れるだけで済んだ。 </p> </section> - <section id="site-hosting-setup--install-softwares"> + <section id="install-softwares"> <h>使うソフトウェアのインストール</h> <codeblock language="shell-session"> <![CDATA[ @@ -247,7 +247,7 @@ remark = "ssh_config に IdentitiesOnly yes を追加" ]]> </codeblock> </section> - <section id="site-hosting-setup--docker"> + <section id="docker"> <h>メインユーザが Docker を使えるように</h> <codeblock language="shell-session"> <![CDATA[ @@ -255,7 +255,7 @@ remark = "ssh_config に IdentitiesOnly yes を追加" ]]> </codeblock> </section> - <section id="site-hosting-setup--open-http-ports"> + <section id="open-http-ports"> <h>HTTP/HTTPS を通す</h> <p> 80 番と 443 番を空ける。 @@ -269,7 +269,7 @@ remark = "ssh_config に IdentitiesOnly yes を追加" ]]> </codeblock> </section> - <section id="site-hosting-setup--clone-repositories"> + <section id="clone-repositories"> <h>リポジトリのクローン</h> <codeblock language="shell-session"> <![CDATA[ @@ -280,7 +280,7 @@ remark = "ssh_config に IdentitiesOnly yes を追加" ]]> </codeblock> </section> - <section id="site-hosting-setup--certbot"> + <section id="certbot"> <h>certbot で証明書取得</h> <codeblock language="shell-session"> <![CDATA[ @@ -289,7 +289,7 @@ remark = "ssh_config に IdentitiesOnly yes を追加" ]]> </codeblock> </section> - <section id="site-hosting-setup--run-server"> + <section id="run-server"> <h>サーバを稼動させる</h> <codeblock language="shell-session"> <![CDATA[ diff --git a/vhosts/blog/content/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3.ndoc b/vhosts/blog/content/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3.ndoc index e6e25f19..45259b85 100644 --- a/vhosts/blog/content/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3.ndoc +++ b/vhosts/blog/content/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3.ndoc @@ -164,13 +164,13 @@ remark = "公開" </section> <section id="commentary"> <h>解説</h> - <section id="commentary--summary"> + <section id="summary"> <h>概要</h> <p> 例外が発生した行数にデータをエンコードし、それを <code>catch</code> で捕まえて表示している。 </p> </section> - <section id="commentary--chain-of-exceptions"> + <section id="chain-of-exceptions"> <h>例外オブジェクトの連鎖</h> <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つの用法がある: @@ -204,7 +204,7 @@ remark = "公開" この知識を元に、トークンの出力部を解析してみる。 </p> </section> - <section id="commentary--output"> + <section id="output"> <h>出力部の解析</h> <p> 出力部をコメントや改行を追加して再掲する: @@ -240,7 +240,7 @@ remark = "公開" それでは、エラーチェインを作る箇所、関数 <code>f()</code> を見ていく。 </p> </section> - <section id="commentary--data-construction"> + <section id="data-construction"> <h>データ構成部の解析</h> <p> <code>f()</code> の定義を再掲する (エラーオブジェクトの行数を利用しているので、一部分だけ抜き出すと値が変わることに注意): diff --git a/vhosts/blog/content/posts/2023-04-01/implementation-of-minimal-png-image-encoder.ndoc b/vhosts/blog/content/posts/2023-04-01/implementation-of-minimal-png-image-encoder.ndoc index 14a24cae..ec39a99f 100644 --- a/vhosts/blog/content/posts/2023-04-01/implementation-of-minimal-png-image-encoder.ndoc +++ b/vhosts/blog/content/posts/2023-04-01/implementation-of-minimal-png-image-encoder.ndoc @@ -88,7 +88,7 @@ remark = "公開" <p> 以降は、<code>writeSignature</code> や <code>writeChunkIhdr</code> などを実装していく。 </p> - <section id="implement-png-encoder--png-signature"> + <section id="png-signature"> <h>PNG signature</h> <p> PNG signature は、PNG 画像の先頭に固定で付与されるバイト列で、8 バイトからなる。 @@ -132,7 +132,7 @@ remark = "公開" <code>encoding/binary</code> パッケージの <code>binary.Write</code> を使い、固定の 8 バイトを書き込む。 </p> </section> - <section id="implement-png-encoder--structure-of-chunk"> + <section id="structure-of-chunk"> <h>Chunk の構造</h> <p> IHDR chunk に進む前に、chunk 一般の構造を確認する。 @@ -209,7 +209,7 @@ remark = "公開" 準備ができたところで、具体的な chunk をエンコードしていく。 </p> </section> - <section id="implement-png-encoder--ihdr-chunk"> + <section id="ihdr-chunk"> <h>IHDR chunk</h> <p> IHDR chunk は最初に配置される chunk である。次のようなデータからなる。 @@ -274,12 +274,12 @@ remark = "公開" ]]> </codeblock> </section> - <section id="implement-png-encoder--idat-chunk"> + <section id="idat-chunk"> <h>IDAT chunk</h> <p> IDAT chunk は、実際の画像データが格納された chunk である。IDAT chunk は deflate アルゴリズムにより圧縮され、zlib 形式で格納される。 </p> - <section id="implement-png-encoder--idat-chunk--zlib"> + <section id="zlib"> <h>Zlib</h> <p> まずは zlib について確認する。おおよそ次のような構造になっている。 @@ -360,7 +360,7 @@ remark = "公開" ]]> </codeblock> </section> - <section id="implement-png-encoder--idat-chunk--image-data"> + <section id="image-data"> <h>画像データ</h> <p> では次に、zlib 形式で格納するデータを用意する。PNG 画像は次のような順にスキャンする。 @@ -394,7 +394,7 @@ remark = "公開" </codeblock> </section> </section> - <section id="implement-png-encoder--iend-chunk"> + <section id="iend-chunk"> <h>IEND chunk</h> <p> 最後に IEND chunk を書き込む。これは PNG 画像の最後に配置される chunk で、PNG のデコーダはこの chunk に出会うとそこでデコードを停止する。 diff --git a/vhosts/blog/content/posts/2023-04-04/phperkaigi-2023-report.ndoc b/vhosts/blog/content/posts/2023-04-04/phperkaigi-2023-report.ndoc index b00d9191..e9ad3d96 100644 --- a/vhosts/blog/content/posts/2023-04-04/phperkaigi-2023-report.ndoc +++ b/vhosts/blog/content/posts/2023-04-04/phperkaigi-2023-report.ndoc @@ -76,7 +76,7 @@ remark = "トークセッションの記事版の執筆を中止" </section> <section id="as-attendee"> <h>参加者として</h> - <section id="as-attendee--recommended-sessions"> + <section id="recommended-sessions"> <h>おすすめセッション</h> <p> 5つのセッションを厳選した。 @@ -115,7 +115,7 @@ remark = "トークセッションの記事版の執筆を中止" ネタバレになるが、最終的に (Go で実装された) 本戦優勝スコアを超えている。 </p> </section> - <section id="as-attendee--phper-challenge"> + <section id="phper-challenge"> <h>PHPer チャレンジ</h> <p> 昨年に引き続き、弊社デジタルサーカス株式会社からのトークン問題の作題を担当した。 @@ -130,7 +130,7 @@ remark = "トークセッションの記事版の執筆を中止" (WIP: 解説ブログ記事執筆中。終わったらここにリンク) </p> </section> - <section id="as-attendee--random-thoughts"> + <section id="random-thoughts"> <h>雑多な感想</h> <p> なんかいろいろ。 diff --git a/vhosts/blog/content/posts/2023-06-25/phpconfuk-2023-report.ndoc b/vhosts/blog/content/posts/2023-06-25/phpconfuk-2023-report.ndoc index 87886bef..39763514 100644 --- a/vhosts/blog/content/posts/2023-06-25/phpconfuk-2023-report.ndoc +++ b/vhosts/blog/content/posts/2023-06-25/phpconfuk-2023-report.ndoc @@ -24,7 +24,7 @@ remark = "公開" </section> <section id="sessions-thoughts"> <h>セッションの感想</h> - <section id="sessions-thoughts--eve"> + <section id="eve"> <h>前夜祭</h> <p> ※セッションの題名と発表者名は、<a href="https://connpass.com/event/282285/">前夜祭イベントの connpass ページ</a>から引用。 @@ -50,7 +50,7 @@ remark = "公開" </li> </ul> </section> - <section id="sessions-thoughts--conference"> + <section id="conference"> <h>カンファレンス</h> <p> ※セッションの題名と発表者名は、<a href="https://fortee.jp/phpconfukuoka-2023/proposal/accepted">カンファレンスの fortee ページ</a>から引用。 diff --git a/vhosts/blog/content/posts/2023-10-02/compile-php-runtime-to-wasm.ndoc b/vhosts/blog/content/posts/2023-10-02/compile-php-runtime-to-wasm.ndoc index f93f3972..19143c44 100644 --- a/vhosts/blog/content/posts/2023-10-02/compile-php-runtime-to-wasm.ndoc +++ b/vhosts/blog/content/posts/2023-10-02/compile-php-runtime-to-wasm.ndoc @@ -66,7 +66,7 @@ remark = "公開" </section> <section id="build"> <h>ビルド</h> - <section id="build--write-c-entrypoint"> + <section id="write-c-entrypoint"> <h>C のエントリポイントを書く</h> <p> 先ほどのコードでも使っていたエントリポイントである <code>php_wasm_run</code> を用意する。 @@ -115,7 +115,7 @@ remark = "公開" 改行を出力せずともバッファを消費させる手段をご存知のかたはご教示願いたい。 </p> </section> - <section id="build--compile-to-wasm"> + <section id="compile-to-wasm"> <h>WebAssembly にコンパイルする</h> <p> それでは WebAssembly にコンパイルしていこう。ここからは <code>Dockerfile</code> 上のコマンドとして操作を示す。 diff --git a/vhosts/blog/content/posts/2023-12-03/isucon-13.ndoc b/vhosts/blog/content/posts/2023-12-03/isucon-13.ndoc index ea4431e7..30b82b9f 100644 --- a/vhosts/blog/content/posts/2023-12-03/isucon-13.ndoc +++ b/vhosts/blog/content/posts/2023-12-03/isucon-13.ndoc @@ -49,26 +49,26 @@ remark = "公開" ISUCON で高スコアを出す戦略については、戦闘力の高い方々が良質な記事を書いてくださっている。 ここでは、上述したような低い目標を達成するための戦略について書こうと思う。 </p> - <section id="strategy--do-not-destroy-environment"> + <section id="do-not-destroy-environment"> <h>環境を破壊しない</h> <p> ミドルウェアの設定やアプリケーションコードなど、変更を加えるあらゆるものは、必ずバックアップを取るか Git で管理する。 復旧不能になって環境ごと作り直すことだけは必ず避ける。 </p> </section> - <section id="strategy--revert-changes-immediately"> + <section id="revert-changes-immediately"> <h>すぐに変更を取り消す</h> <p> それでも壊してしまったときは、即座に変更を取り消す。壊れた理由を調べることに固執しない。 </p> </section> - <section id="strategy--do-small-deployment"> + <section id="do-small-deployment"> <h>小さくデプロイする</h> <p> 一度に複数の変更を加えず、可能な限り小さな単位でデプロイする。そしてその都度ベンチマークを走らせ、整合性チェックが通るかどうかを (当然速くなっているかどうかも) 確かめる。 </p> </section> - <section id="strategy--use-familiar-tools"> + <section id="use-familiar-tools"> <h>使い慣れた道具を使う</h> <p> 使用する言語、ミドルウェア、ツール類を、使い慣れたものに限定する。 diff --git a/vhosts/blog/content/posts/2024-03-17/phperkaigi-2024-report.ndoc b/vhosts/blog/content/posts/2024-03-17/phperkaigi-2024-report.ndoc index 557cf3ff..c5eee896 100644 --- a/vhosts/blog/content/posts/2024-03-17/phperkaigi-2024-report.ndoc +++ b/vhosts/blog/content/posts/2024-03-17/phperkaigi-2024-report.ndoc @@ -68,7 +68,7 @@ remark = "Wasm ランタイムの進捗について追記" </section> <section id="as-attendee"> <h>参加者として</h> - <section id="as-attendee--my-best-session"> + <section id="my-best-session"> <h>マイベストセッション</h> <p> <a href="https://fortee.jp/phperkaigi-2024/proposal/ac59d0dd-795a-47cb-ba59-c0b1772d00cc">RubyVM を PHP で実装する〜Hello World を出力するまで〜</a> (めもりー さん) diff --git a/vhosts/blog/content/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd.ndoc b/vhosts/blog/content/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd.ndoc index 028cbbb0..d65fffb5 100644 --- a/vhosts/blog/content/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd.ndoc +++ b/vhosts/blog/content/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd.ndoc @@ -26,7 +26,7 @@ remark = "ブログ記事として一般公開" </p> <section id="background"> <h>前提</h> - <section id="background--gitlab-ci-cd"> + <section id="gitlab-ci-cd"> <h>GitLab CI/CD について</h> <p> GitLab CI/CD では、Docker executor を用いて任意の Docker image 上でスクリプトを走らせることができる。 @@ -68,7 +68,7 @@ remark = "ブログ記事として一般公開" 失敗するコマンドをパイプに接続した。通常 Bash では、パイプの最後のコマンドの exit code が全体の exit code になる。 </p> </section> - <section id="background--pipefail-option"> + <section id="pipefail-option"> <h><code>pipefail</code> オプションについて</h> <p> 前述したようなケースにおいて、途中で失敗したときに全体を失敗させるには、<code>pipefail</code> オプションを有効にする。 diff --git a/vhosts/blog/content/posts/2024-12-04/cohackpp-report.ndoc b/vhosts/blog/content/posts/2024-12-04/cohackpp-report.ndoc index a54ae113..5d77af55 100644 --- a/vhosts/blog/content/posts/2024-12-04/cohackpp-report.ndoc +++ b/vhosts/blog/content/posts/2024-12-04/cohackpp-report.ndoc @@ -56,7 +56,7 @@ remark = "「育てた」枠・「育てられた」枠を勘違いして逆に </section> <section id="lt"> <h>LT</h> - <section id="lt--prepare"> + <section id="prepare"> <h>合戦準備</h> <p> さて、時を合戦の前に戻しまして、両陣営の登壇者が発表され徐々に謎のイベントの輪郭が見えてきた頃、asumikam さんから次のような連絡を受けました。 @@ -66,7 +66,7 @@ remark = "「育てた」枠・「育てられた」枠を勘違いして逆に 最初は直近のカンファレンスに出して落選したプロポーザルテーマを LT に編集して話そうとしていたのですが、この機会でなければ話せない・この機会で話すことに意味があるテーマにしようとネタ出しをおこない、最終的に次のテーマでの登壇となりました。 </p> </section> - <section id="lt--battle"> + <section id="battle"> <h>いざ尋常に勝負</h> <p> 当日は、「プログラミングマナー講座」と題して発表をおこないました。 diff --git a/vhosts/blog/content/posts/2025-01-08/phperkaigi-2023-tokens-q1.ndoc b/vhosts/blog/content/posts/2025-01-08/phperkaigi-2023-tokens-q1.ndoc index 37345849..ede3fdfb 100644 --- a/vhosts/blog/content/posts/2025-01-08/phperkaigi-2023-tokens-q1.ndoc +++ b/vhosts/blog/content/posts/2025-01-08/phperkaigi-2023-tokens-q1.ndoc @@ -70,7 +70,7 @@ remark = "読みやすさのため一部の文言を調整" </section> <section id="commentary"> <h>解説</h> - <section id="commentary--read-as-image"> + <section id="read-as-image"> <h>画像として解釈する</h> <p> まずは素直に画像として見てみよう。 @@ -89,7 +89,7 @@ remark = "読みやすさのため一部の文言を調整" 他の PHPer トークンの中から適切な1つを見つけだし、「パスワード」として渡すことで答えとなる PHPer トークンが得られるというわけだ。 </p> </section> - <section id="commentary--password"> + <section id="password"> <h>パスワード</h> <p> 不正なパスワードを使って実行してみると、次のようなエラーメッセージが表示される。 @@ -115,7 +115,7 @@ remark = "読みやすさのため一部の文言を調整" これは私のミスである。 </p> </section> - <section id="commentary--png-steganography"> + <section id="png-steganography"> <h>PNG ステガノグラフィ</h> <p> QR コードも言っているように、このファイルは PNG 画像であるにもかかわらず PHP で実行することができる。なぜこのようなことが可能なのか。 @@ -185,7 +185,7 @@ remark = "読みやすさのため一部の文言を調整" なお、このように PNG 画像などに本来のデータとは異なる別のデータを隠すことを「ステガノグラフィ」(<a href="https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%86%E3%82%AC%E3%83%8E%E3%82%B0%E3%83%A9%E3%83%95%E3%82%A3%E3%83%BC">Wikipedia「ステガノグラフィー」</a>) と呼ぶ。 </p> </section> - <section id="commentary--php-program"> + <section id="php-program"> <h>実行される PHP プログラム</h> <p> 画像の正体がわかったところで、画像に隠されていた PHP プログラムについて見ていこう。 @@ -318,7 +318,7 @@ remark = "読みやすさのため一部の文言を調整" QR コード中央のカラフルな部分が Piet の命令になっている。 </p> </section> - <section id="commentary--piet-source-code"> + <section id="piet-source-code"> <h>Piet のソースコード</h> <p> さて、Piet でどのようなコードが書かれて (いや、描かれて) いるのかを解説したいところだが、今の私にはできそうにない。 @@ -377,7 +377,7 @@ remark = "読みやすさのため一部の文言を調整" そういうわけでこの Piet インタプリタは完全な Piet インタプリタではなく、「403 Forbidden」というテキストを絶対に出力できない。 </p> </section> - <section id="commentary--misc"> + <section id="misc"> <h>その他小ネタ</h> <p> ここまでで問題の核心部分は説明し終えたので、ここからは残った小ネタを紹介しておく。 diff --git a/vhosts/blog/content/posts/2025-01-26/yaml-breaking-changes-between-v1-1-and-v1-2.ndoc b/vhosts/blog/content/posts/2025-01-26/yaml-breaking-changes-between-v1-1-and-v1-2.ndoc index cb8add2c..74c2c14e 100644 --- a/vhosts/blog/content/posts/2025-01-26/yaml-breaking-changes-between-v1-1-and-v1-2.ndoc +++ b/vhosts/blog/content/posts/2025-01-26/yaml-breaking-changes-between-v1-1-and-v1-2.ndoc @@ -33,7 +33,7 @@ remark = "ブログ記事として一般公開" </section> <section id="breaking-changes"> <h>主な破壊的変更</h> - <section id="breaking-changes--boolean-literals"> + <section id="boolean-literals"> <h>Boolean としてパースされるトークンが <code>true</code> / <code>false</code> とその亜種のみに</h> <p> この変更の影響が最も大きいと思われる。 @@ -41,7 +41,7 @@ remark = "ブログ記事として一般公開" YAML 1.2 では、<code>true</code> と <code>false</code>、それらの大文字バージョン (<code>True</code>、<code>TRUE</code>、<code>False</code>、<code>FALSE</code>) のみが boolean としてパースされるようになった。 </p> </section> - <section id="breaking-changes--octal-literals"> + <section id="octal-literals"> <h>八進数リテラルには <code>0o</code> が必須に</h> <p> C 言語などでは、<code>0</code> から始まる数字の列を八進数としてパースする。 @@ -49,7 +49,7 @@ remark = "ブログ記事として一般公開" プログラミング言語では、Python や Haskell、Swift、Rust などがこの記法を採用している。 </p> </section> - <section id="breaking-changes--merging"> + <section id="merging"> <h><code><<</code> によるマージが不可能に</h> <p> YAML 1.1 では、<code><<</code> という文字列をキーに指定することで、マップをマージすることができた。 @@ -70,7 +70,7 @@ remark = "ブログ記事として一般公開" 1.2 からはこれができなくなる。 </p> </section> - <section id="breaking-changes--number-separator"> + <section id="number-separator"> <h>数字を <code>_</code> で区切るのが禁止に</h> <p> <code>1234567</code> を <code>1_234_567</code> と書けなくなった。 diff --git a/vhosts/blog/content/posts/2025-03-28/http-1-1-send-multiple-same-headers.ndoc b/vhosts/blog/content/posts/2025-03-28/http-1-1-send-multiple-same-headers.ndoc index 002463aa..8fe1a9b0 100644 --- a/vhosts/blog/content/posts/2025-03-28/http-1-1-send-multiple-same-headers.ndoc +++ b/vhosts/blog/content/posts/2025-03-28/http-1-1-send-multiple-same-headers.ndoc @@ -37,7 +37,7 @@ remark = "ブログ記事として一般公開" </section> <section id="specification"> <h>仕様</h> - <section id="specification--sender"> + <section id="sender"> <h>送信側</h> <blockquote> A sender MUST NOT generate multiple header fields with the same field @@ -51,7 +51,7 @@ remark = "ブログ記事として一般公開" ただし、header field の値がコンマ区切りのリストとして定義されているか、header field がよく知られた例外 (後述) である場合はその限りでない。 </p> </section> - <section id="specification--recipient"> + <section id="recipient"> <h>受信側</h> <blockquote> A recipient MAY combine multiple header fields with the same field @@ -70,7 +70,7 @@ remark = "ブログ記事として一般公開" よって、プロキシは、メッセージを転送する際、header field の順序を変えてはならない (MUST NOT)。 </p> </section> - <section id="specification--exception"> + <section id="exception"> <h>例外ケース: Set-Cookie</h> <blockquote> Note: In practice, the "Set-Cookie" header field ([<a href="https://datatracker.ietf.org/doc/html/rfc6265">RFC6265</a>]) often @@ -91,7 +91,7 @@ remark = "ブログ記事として一般公開" おそらく、「送信側」のところで書かれている「よく知られた例外」の一つがこれだと思われる。 </p> </section> - <section id="specification--comma-separated-list"> + <section id="comma-separated-list"> <h>どの header field がコンマ区切りのリストなのか</h> <p> 上記のように、同じ field name を持つ header field を複数回送れるかどうかは、その header field がコンマ区切りのリストとして定義されているかどうかで決まる。では、特定の header field がその条件を満たしているかどうか知りたいときは、何を見ればよいのか。 diff --git a/vhosts/blog/nuldoc-src/ndoc/to_html.ts b/vhosts/blog/nuldoc-src/ndoc/to_html.ts index d4630d59..a82f0333 100644 --- a/vhosts/blog/nuldoc-src/ndoc/to_html.ts +++ b/vhosts/blog/nuldoc-src/ndoc/to_html.ts @@ -94,14 +94,46 @@ function transformLinkLikeToAnchorElement(doc: Document) { } function transformSectionIdAttribute(doc: Document) { - forEachChildRecursively(doc.root, (n) => { - if (n.kind !== "element" || n.name !== "section") { + const sectionStack: string[] = []; + const usedIds = new Set<string>(); + + const processNode = (n: Node) => { + if (n.kind !== "element") { return; } - const idAttr = n.attributes.get("id"); - n.attributes.set("id", `section--${idAttr}`); - }); + if (n.name === "section") { + const idAttr = n.attributes.get("id"); + if (!idAttr) { + return; + } + + let newId: string; + if (sectionStack.length === 0) { + newId = `section--${idAttr}`; + } else { + newId = `section--${sectionStack.join("--")}--${idAttr}`; + } + + if (usedIds.has(newId)) { + throw new NuldocError( + `[nuldoc.tohtml] Duplicate section ID: ${newId}`, + ); + } + + usedIds.add(newId); + n.attributes.set("id", newId); + sectionStack.push(idAttr); + + forEachChild(n, processNode); + + sectionStack.pop(); + } else { + forEachChild(n, processNode); + } + }; + + forEachChild(doc.root, processNode); } function setSectionTitleAnchor(doc: Document) { diff --git a/vhosts/blog/public/posts/2021-03-30/phperkaigi-2021/index.html b/vhosts/blog/public/posts/2021-03-30/phperkaigi-2021/index.html index e70cf152..bb3f44cd 100644 --- a/vhosts/blog/public/posts/2021-03-30/phperkaigi-2021/index.html +++ b/vhosts/blog/public/posts/2021-03-30/phperkaigi-2021/index.html @@ -77,8 +77,8 @@ 発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。 </p> - <section id="section--report-legend"> - <h3><a href="#section--report-legend">凡例</a></h3> + <section id="section--report--legend"> + <h3><a href="#section--report--legend">凡例</a></h3> <blockquote> <p> 発表・スライドのメモ (引用ではない) |
