<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>KJ&apos;s Site</title><description>KJの技術ブログ</description><link>https://blog.kj-dev.net/</link><item><title>『世界一やさしい 会計の教科書 1年生』を読んだ</title><link>https://blog.kj-dev.net/posts/book-review-accounting-textbook-first-year/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/book-review-accounting-textbook-first-year/</guid><description>登川雄太さんの『世界一やさしい 会計の教科書 1年生』を読んだメモ</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate><content:encoded/></item><item><title>Understanding is the new bottleneck</title><link>https://blog.kj-dev.net/posts/l/2026/07/understanding-is-the-new-bottleneck/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2026/07/understanding-is-the-new-bottleneck/</guid><pubDate>Mon, 06 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;understanding-is-the-new-bottleneck-by-geoffrey-litt&quot;&gt;&lt;a href=&quot;https://geoffreylitt.com/2026/07/02/understanding-is-the-new-bottleneck.html&quot;&gt;Understanding is the new bottleneck&lt;/a&gt; by &lt;a href=&quot;https://geoffreylitt.com/&quot;&gt;Geoffrey Litt&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AIが書いたコードを人間が理解するための方法論。素晴らしい記事。&lt;/p&gt;
&lt;p&gt;そもそもなぜコードを人間が理解する必要があるのだろうか？
それは、コードを検証するためだけではなく、Agentのループに参加するため、共創するため。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;And the understanding you have of the system is part of your ability to come up with the next idea to evolve it.&lt;/p&gt;&lt;p&gt;You need a rich set of concepts in your mind to think creatively and fluently about how to move something forward. If you’re lacking that fluency, your ability to participate in the project is meaningfully limited.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;当然、ボトルネックになるのは人間側の理解速度。
そのための工夫が三つ出てくる。特に勉強になったのは、AIに説明をさせるだけでなく、理解を確認するクイズを作らせること。&lt;/p&gt;
&lt;p&gt;ドキュメントを読むだけでは理解したことにはならない。だからクイズを埋め込ませる。&lt;/p&gt;
&lt;p&gt;この考えを使った&lt;a href=&quot;https://gist.github.com/geoffreylitt/a29df1b5f9865506e8952488eac3d524&quot;&gt;explain-diff&lt;/a&gt;というskillsも公開してくれている。&lt;/p&gt;</content:encoded></item><item><title>GitNationの動画の文字起こしを取得する</title><link>https://blog.kj-dev.net/posts/gitnation-vimeo-subtitles-with-yt-dlp/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/gitnation-vimeo-subtitles-with-yt-dlp/</guid><description>GitNation の動画ページから Vimeo 埋め込みを探して字幕を取得する</description><pubDate>Sun, 05 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://gitnation.com/talks/all&quot;&gt;GitNation&lt;/a&gt; のTalk動画の文字起こしを取得できないかを調べた。&lt;/p&gt;
&lt;p&gt;自分でブラウザの開発者ツールを開いてページを解析してみるが、上手い方法が見つからない。&lt;/p&gt;
&lt;p&gt;これは難しいか？と感じながらも、Codex Appのブラウザである動画ページを開いた。
「このページの文字起こしを取得する方法を考えて」と指示を出したところ、ページ HTML の中に Vimeo の埋め込み URL があることを発見してくれた。&lt;/p&gt;
&lt;p&gt;そこからはCodexの提案に乗り、&lt;code&gt;yt-dlp&lt;/code&gt;を使うことで字幕を取得することができた。
（yt-dlpは便利なことにYoutube以外のプラットフォームもサポートしている）&lt;/p&gt;
&lt;p&gt;スクリプトは&lt;a href=&quot;https://kj-9.github.io/tools/&quot;&gt;tools&lt;/a&gt; に &lt;code&gt;gitnation-subs.py&lt;/code&gt; として置いた。&lt;/p&gt;
&lt;p&gt;手元に &lt;code&gt;uv&lt;/code&gt; が入っていれば、&lt;code&gt;uv run&lt;/code&gt; で URL から直接実行できる。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;uv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; https://kj-9.github.io/tools/python/gitnation-subs.py&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --help&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;字幕一覧だけ確認する場合。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;uv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; https://kj-9.github.io/tools/python/gitnation-subs.py&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt;  --list&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;  &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;&amp;#x3C;GitNation page URL&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;英語字幕を保存する場合。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;uv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; https://kj-9.github.io/tools/python/gitnation-subs.py&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt;  -l&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; en&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt;  -P&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; ~/Downloads&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;  &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;&amp;#x3C;GitNation page URL&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded></item><item><title>Parse, don&apos;t validate</title><link>https://blog.kj-dev.net/posts/l/2026/06/parse-dont-validate/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2026/06/parse-dont-validate/</guid><pubDate>Sat, 27 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;parse-dont-validate-by-alexis-king&quot;&gt;&lt;a href=&quot;https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/&quot;&gt;Parse, don’t validate&lt;/a&gt; by &lt;a href=&quot;https://x.com/lexi_lambda&quot;&gt;Alexis King&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;プログラムを実装していて、いたるところで値のバリデーションやチェックをしていると感じたことはないだろうか。&lt;/p&gt;
&lt;p&gt;そして、氾濫するバリデーションをどうやって整理したものか頭を抱えたことはないだろうか。&lt;/p&gt;
&lt;p&gt;そんな悩みに、この記事は方針を示してくれる。一度読んでおきたい記事だ。&lt;/p&gt;
&lt;p&gt;validateとは値をチェックすること。
parseとはvalidateしてより制約の強い型に変換すること。&lt;/p&gt;
&lt;p&gt;validateだけでは情報をロスしてしまい、勿体無い。parseして型に落とす。理想的には後続処理に渡す前に。そうすることで、後続の処理で同じチェックを何度もする必要がなくなる。&lt;/p&gt;
&lt;p&gt;記事ではより詳しい説明と、実践的なアドバイスも書かれている。&lt;/p&gt;
&lt;h2 id=&quot;現実との折り合い&quot;&gt;現実との折り合い&lt;/h2&gt;
&lt;p&gt;ただし、すべてを「parseして型に落とす」で綺麗に解決できるわけではない。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.ploeh.dk/2022/08/22/can-types-replace-validation/&quot;&gt;Can types replace validation?&lt;/a&gt; もあわせて読むと、現実のアプリケーションでは別の都合もあることが分かる。&lt;/p&gt;
&lt;p&gt;たとえば、ユーザー入力では複数のエラーをまとめて表示したいことがある。言語の型システムだけでは表現しにくい制約もある。外部ライブラリやフレームワークとの境界で、理想的なドメイン型だけを扱えないこともある。&lt;/p&gt;
&lt;h2 id=&quot;typescript-や-python-で考える&quot;&gt;TypeScript や Python で考える&lt;/h2&gt;
&lt;p&gt;現実的には、言語に搭載されている機能だけに頼るのではなく、ある程度フレームワークを活用するのが良いと思う。TypeScript なら &lt;a href=&quot;https://zod.dev&quot;&gt;Zod&lt;/a&gt;、Python なら &lt;a href=&quot;https://pydantic.dev/docs/validation/latest/get-started/&quot;&gt;Pydantic&lt;/a&gt;のようなライブラリを使う。&lt;/p&gt;
&lt;p&gt;Pydanticでは、標準的に複数のバリデーションエラーを一度に取得できる:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl mt-8&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;#!/usr/bin/env -S uv run&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; /// script&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# requires-python = &quot;&gt;=3.12&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# dependencies = [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;#   &quot;pydantic[email]&gt;=2.11&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; ///&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; pydantic &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    BaseModel&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    EmailStr&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    Field&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    ValidationError&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#FFCB8B&quot;&gt; AdultUser&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;BaseModel&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#C5E478&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; Field&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D7DBE0&quot;&gt;min_length&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    age&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#C5E478&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; Field&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D7DBE0&quot;&gt;ge&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;18&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    email&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; EmailStr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;    AdultUser&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        **&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;            &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;            &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;age&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;15&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;            &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;xxx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;except&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; ValidationError &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; e&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;❌ Validation failed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#F78C6C&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; e&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;errors&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;        path &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#C5E478&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;loc&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;&quot;• &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;&quot;    入力値 : &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;error.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;!r&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;&quot;    理由   : &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;msg&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;absolute py-1 text-foreground text-xs font-medium leading-4 pl-4 pr-2 before:inline-block before:size-1 before:bg-green-500 before:rounded-full before:absolute before:top-[45%] before:left-2 left-2 top-(--file-name-offset) border rounded-md bg-background&quot;&gt;main.py&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;実行結果:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;❯ uv run main.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;❌ Validation failed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;• name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    入力値 : &apos;a&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    理由   : String should have at least 3 characters&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;• age&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    入力値 : 15&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    理由   : Input should be greater than or equal to 18&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;• email&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    入力値 : &apos;xxx&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    理由   : value is not a valid email address: An email address must have an @-sign.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一度のバリデーションで複数のエラーを取得できるので、ユーザーに対してまとめてエラーを表示することも容易だ。&lt;/p&gt;
&lt;p&gt;その他にもPydanticには豊富な機能が存在するので、選択肢として覚えておきたい。&lt;/p&gt;</content:encoded></item><item><title>Kindleハイライトのエクスポート制限を回避してコピーする</title><link>https://blog.kj-dev.net/posts/l/2026/05/copy-kindle-highlights-beyond-export-limits/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2026/05/copy-kindle-highlights-beyond-export-limits/</guid><pubDate>Tue, 12 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;how-to-copy-and-paste-kindle-highlights-beyond-the-export-limits-by-glasp-tutorial&quot;&gt;&lt;a href=&quot;https://glasp.co/posts/how-to-copy-and-paste-kindle-highlights-beyond-the-export-limits&quot;&gt;How to Copy and Paste Kindle Highlights Beyond the Export Limits&lt;/a&gt; by &lt;a href=&quot;https://glasp.co/posts/glasp-tutorial&quot;&gt;Glasp Tutorial&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Kindle Cloud Reader と Glasp のブラウザ拡張を使って、Kindle のハイライトをまとめてコピーしたり、TXT / CSV / Markdown としてエクスポートしたりする手順。&lt;/p&gt;
&lt;p&gt;Kindle のハイライトは外に出そうとすると制限にぶつかることがあるので、こういう逃がし方があるのはありがたい。&lt;/p&gt;</content:encoded></item><item><title>macOS + OBSでChatGPT Atlasを録画したら音が入らなかった</title><link>https://blog.kj-dev.net/posts/obs-macos-browser-audio-capture/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/obs-macos-browser-audio-capture/</guid><description>macOSのOBSでChatGPT Atlasを録画したとき、映像は撮れているのに音声がほぼ無音だったケースのメモ。</description><pubDate>Sat, 09 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;OBS StudioでChatGPT Atlasの画面を録画したところ、映像は撮れていたのに音声が入っていなかった。&lt;/p&gt;
&lt;p&gt;結論としては、ChatGPT AtlasとOBSの相性が悪かったっぽい。
同じ設定のままChromeで録画すると音が入った。&lt;/p&gt;
&lt;h2 id=&quot;環境&quot;&gt;環境&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;macOS 26.4.1&lt;/li&gt;
&lt;li&gt;OBS Studio 32.1.2&lt;/li&gt;
&lt;li&gt;&lt;code&gt;macOS Screen Capture&lt;/code&gt; ソースを使用&lt;/li&gt;
&lt;li&gt;録画対象はChatGPT Atlasの画面と音&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OBS公式ドキュメントを見る限り、OBS Studio 30以降かつmacOS 13以降では、&lt;code&gt;macOS Audio Capture Source&lt;/code&gt; でデスクトップ全体またはアプリ単位の音声をキャプチャできる。
また、&lt;code&gt;macOS Screen Capture&lt;/code&gt; でもmacOS 13以降なら音声をキャプチャできる。&lt;/p&gt;
&lt;p&gt;なので、今回はBlackHoleなどの仮想オーディオデバイスは入れずに試した。&lt;/p&gt;
&lt;p&gt;参考:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://obsproject.com/kb/macos-desktop-audio-capture-guide&quot;&gt;macOS Desktop Audio Capture Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://obsproject.com/kb/macos-screen-capture-source&quot;&gt;macOS Screen Capture Source&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;何が起きたか&quot;&gt;何が起きたか&lt;/h2&gt;
&lt;p&gt;ChatGPT Atlasの画面と音をOBSで録画したところ、映像は撮れているのに音声がほぼ無音だった。&lt;/p&gt;
&lt;p&gt;OBSの設定:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;macOS Screen Capture&lt;/code&gt; はミュートされていない&lt;/li&gt;
&lt;li&gt;録画トラック1に音声が割り当たっている&lt;/li&gt;
&lt;li&gt;OBSの録画ファイルにはAAC音声トラックが存在するがほぼ無音&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;原因っぽいもの&quot;&gt;原因っぽいもの&lt;/h2&gt;
&lt;p&gt;今回の切り分けでは、ChatGPT Atlasだと音が取れず、Chromeだと音が取れた。
同じOBS設定でブラウザだけ変えている。&lt;/p&gt;
&lt;p&gt;なので原因はOBSの録画設定というより、macOSの音声キャプチャとブラウザ側の相性に見える。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;macOS Screen Capture&lt;/code&gt; はScreenCaptureKitベースのソースなので、そのあたりでブラウザやアプリによって取れたり取れなかったりすることがあるっぽい。&lt;/p&gt;
&lt;h2 id=&quot;録画前の確認ポイント&quot;&gt;録画前の確認ポイント&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;ソースに &lt;code&gt;macOS Screen Capture&lt;/code&gt; を追加&lt;/li&gt;
&lt;li&gt;録画したいブラウザを選ぶ&lt;/li&gt;
&lt;li&gt;ブラウザで音を再生する&lt;/li&gt;
&lt;li&gt;OBSの音声ミキサーでメーターが動くか確認する&lt;/li&gt;
&lt;li&gt;短くテスト録画して、実際に音が入っているか確認する&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;メーターが動いていない、または録画ファイルがほぼ無音の場合は、OBS設定だけでなくブラウザも疑う。
今回のようにChatGPT Atlasでダメでも、Chromeならそのまま解消することがある。&lt;/p&gt;</content:encoded></item><item><title>Isometric NYC（ピクセルアートで作るNYCの等角地図）</title><link>https://blog.kj-dev.net/posts/l/2026/01/isometric-nyc/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2026/01/isometric-nyc/</guid><pubDate>Sat, 31 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;isometric-nyc&quot;&gt;&lt;a href=&quot;https://cannoneyed.com/projects/isometric-nyc&quot;&gt;Isometric NYC&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;NYC全域を等角（isometric）のピクセルアートで可視化した巨大マップの制作記録。&lt;/p&gt;
&lt;p&gt;終始生成AIを駆使して取り組んでいるが、必ずしも全てがスマートに進んだわけではなく、
試行錯誤・悪戦苦闘しながらやりきっているのがすごい。&lt;/p&gt;
&lt;p&gt;インタラクティブな完成版はこちら: &lt;a href=&quot;https://isometric.nyc&quot;&gt;isometric.nyc&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>DuckLake デバッグ備忘録</title><link>https://blog.kj-dev.net/posts/l/2025/11/developing-ducklake/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/11/developing-ducklake/</guid><pubDate>Sun, 23 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;/h2&gt;
&lt;p&gt;duckdbのエクステンション、ducklakeをローカルで開発・デバッグする際の備忘録。&lt;/p&gt;
&lt;p&gt;PRを出す際に探り探りでやっていたので、次回以降のために記録を残しておく。&lt;/p&gt;
&lt;h2 id=&quot;参考資料&quot;&gt;参考資料&lt;/h2&gt;
&lt;p&gt;以下は一読すると良い:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/duckdb/ducklake&quot;&gt;ducklakeのREADME&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;duckdb公式Doc
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://duckdb.org/docs/stable/dev/sqllogictest/overview&quot;&gt;Testing&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;SQLLogicTest の使い方が解説されているので一読すると良い&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://duckdb.org/docs/stable/internals/overview&quot;&gt;Internals&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;DuckLake のアーキテクチャやコンポーネントの説明がある&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;debug-ビルドの作成&quot;&gt;debug ビルドの作成&lt;/h2&gt;
&lt;p&gt;ducklakeをクローンして、git submoduleを初期化し、debugビルドを作成する:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; submodule&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; update&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --init&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --recursive&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # 初回のみ&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;GEN&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;ninja&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; make&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; debug&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;差分を反映するには再ビルドが必要となるので、ソースを修正したら&lt;code&gt;GEN=ninja make debug&lt;/code&gt; でデバッグビルドを更新する。&lt;/p&gt;
&lt;h2 id=&quot;テスト実行&quot;&gt;テスト実行&lt;/h2&gt;
&lt;p&gt;buildをすると、テストを実行できるプログラムが &lt;code&gt;build/debug/test/unittest&lt;/code&gt; に生成される。&lt;/p&gt;
&lt;p&gt;テストは以下のように実行する:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;./build/debug/test/unittest&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; test/sql/merge/merge_partition_update.test&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;build/debug/test/unittest&lt;/code&gt; がデバッグビルドのテスト実行バイナリ。&lt;/li&gt;
&lt;li&gt;引数に SQLLogicTest のテストファイルを指定して実行する。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;より細かい&lt;a href=&quot;https://duckdb.org/docs/stable/dev/sqllogictest/debugging#triggering-which-tests-to-run&quot;&gt;テストの流し方&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;vscode-で-デバッグ&quot;&gt;VSCode で デバッグ&lt;/h2&gt;
&lt;p&gt;launch.jsonを設定して、VSCodeのデバッガでDuckLakeのソースコードをステップ実行できるようにする。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://zenn.dev/link/comments/954a247fb35d2b&quot;&gt;記事&lt;/a&gt;を参考に作成:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl mt-8&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  &quot;version&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;0.2.0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  &quot;configurations&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;name&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;(lldb) test_simple_projection&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;cppdbg&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;request&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;launch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;program&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;${workspaceFolder}/build/debug/test/unittest&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;args&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;test/sql/merge/merge_partition_update.test&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;stopAtEntry&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#FF5874&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;cwd&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;${workspaceFolder}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;MIMode&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;lldb&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;externalConsole&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#FF5874&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;absolute py-1 text-foreground text-xs font-medium leading-4 pl-4 pr-2 before:inline-block before:size-1 before:bg-green-500 before:rounded-full before:absolute before:top-[45%] before:left-2 left-2 top-(--file-name-offset) border rounded-md bg-background&quot;&gt;.vscode/launch.json&lt;/span&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;program&lt;/code&gt; に &lt;code&gt;build/debug/test/unittest&lt;/code&gt; を指定し、&lt;code&gt;args&lt;/code&gt; で実行したい SQLLogicTest（例: &lt;code&gt;test/sql/merge/merge_partition_update.test&lt;/code&gt;）を渡す。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cwd&lt;/code&gt; はリポジトリのルートに設定しておく。&lt;/li&gt;
&lt;li&gt;これで VSCode のブレークポイントが DuckLake のソースにヒットするようになる。
&lt;ul&gt;
&lt;li&gt;追いたいファイル（例: &lt;code&gt;src/storage/ducklake_update.cpp&lt;/code&gt;）にブレークポイントを置く。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;設定した &lt;code&gt;launch.json&lt;/code&gt; で VSCode デバッガを起動し、テストを実行しながらステップ実行できる。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SQLテストは単スレッドで走らせるとデバッグしやすい。どうやらデフォルトでは並列スレッドで実行されるようなので、いちいちスレッドが切り替わってしまい、デバッグが困難になる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SQLogicTest の冒頭に &lt;code&gt;PRAGMA threads=1;&lt;/code&gt; を追加し、並列実行を抑止する。&lt;/li&gt;
&lt;li&gt;デバッガで追いやすくなり、並列化によるログの混乱や競合を避けられる。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Git rerere (Reuse Recorded Resolution) テクニックとヒント</title><link>https://blog.kj-dev.net/posts/git-rerere-technique-and-tips/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/git-rerere-technique-and-tips/</guid><description>Gitのrerere（reuse recorded resolution）は、マージやリベースの際に発生したコンフリクト（競合）の解決方法をGit自身に記憶させ、同じコンフリクトが将来再び発生したときに自動で再適用させるための強力な機能である。</description><pubDate>Mon, 06 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Gitのrerere（reuse recorded resolution）は、マージやリベースの際に発生したコンフリクト（競合）の解決方法をGit自身に記憶させ、同じコンフリクトが将来再び発生したときに自動で再適用させるための強力な機能である。特に長期にわたるブランチ開発や、頻繁なリベースを行うワークフローで、手作業によるコンフリクト解決の繰り返しを防ぎ、作業効率を大幅に向上させる。&lt;/p&gt;
&lt;h2 id=&quot;1-rerereの基本と有効化&quot;&gt;1. rerereの基本と有効化&lt;/h2&gt;
&lt;h3 id=&quot;a-rerereの仕組み&quot;&gt;A. rerereの仕組み&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;衝突の記録（Preimage）&lt;/strong&gt;: コンフリクトが発生すると、Gitは衝突前のファイルの状態を&lt;code&gt;.git/rr-cache/&lt;/code&gt;ディレクトリにハッシュ値で記録する（これをPreimageと呼ぶ）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解決の記録（Postimage）&lt;/strong&gt;: ユーザーがコンフリクトを手動で解決し、&lt;code&gt;git add&lt;/code&gt;してから&lt;code&gt;git commit&lt;/code&gt;（または&lt;code&gt;git rebase --continue&lt;/code&gt;など）を行うと、Gitはその解決後の状態を記録する（Postimage）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解決の再利用&lt;/strong&gt;: 次回、同じPreimageを持つコンフリクトに遭遇した場合、Gitは記録されたPostimageを自動的に適用する。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;b-有効化の方法必須&quot;&gt;B. 有効化の方法（必須）&lt;/h3&gt;
&lt;p&gt;rerereはデフォルトでは無効になっているため、以下のコマンドで有効にする必要がある。&lt;/p&gt;

















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;スコープ&lt;/th&gt;&lt;th&gt;コマンド&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;グローバル（すべてのリポジトリ）&lt;/td&gt;&lt;td&gt;&lt;code&gt;git config --global rerere.enabled true&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ローカル（現在のリポジトリのみ）&lt;/td&gt;&lt;td&gt;&lt;code&gt;git config rerere.enabled true&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;2-rerereの応用テクニックと活用シーン&quot;&gt;2. rerereの応用テクニックと活用シーン&lt;/h2&gt;
&lt;h3 id=&quot;a-長期ブランチの頻繁な同期&quot;&gt;A. 長期ブランチの頻繁な同期&lt;/h3&gt;
&lt;p&gt;長期フィーチャーブランチ（開発に時間がかかるブランチ）を&lt;code&gt;main&lt;/code&gt;や&lt;code&gt;develop&lt;/code&gt;ブランチに追従させるために、定期的にリベースやマージを行う場合、同じコンフリクトが何度も発生しがちである。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;活用方法&lt;/strong&gt;: 一度目のリベース/マージでコンフリクトを解決すれば、二度目以降の追従作業ではrerereが自動で解決を適用してくれる。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; checkout&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; feature-branch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# 初回：ここでコンフリクトを解決・コミットし、rerereに記憶させる&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; rebase&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# 2回目以降：自動解決される&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; rebase&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;b-テストマージとマージコミットの破棄&quot;&gt;B. 「テストマージ」とマージコミットの破棄&lt;/h3&gt;
&lt;p&gt;フィーチャーブランチが&lt;code&gt;main&lt;/code&gt;と結合した状態で正しく動作するか確認するために一時的なマージを行い、履歴をクリーンに保つためにそのマージコミットを破棄するワークフロー（“Test Merge”）がある。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;テストマージを実行し、コンフリクトを解決・コミットする。(rerereが解決を記録)&lt;/li&gt;
&lt;li&gt;テストを実行し、問題ないことを確認する。&lt;/li&gt;
&lt;li&gt;マージコミットを破棄する。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; reset&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --hard&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; HEAD^&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最終的な正式マージ（またはリベース）を行う際、rerereが以前の解決を再適用するため、手動での再解決が不要になる。&lt;/p&gt;
&lt;h2 id=&quot;3-rerere利用時のヒントと注意点&quot;&gt;3. rerere利用時のヒントと注意点&lt;/h2&gt;
&lt;h3 id=&quot;a-自動解決後の確認を怠らない&quot;&gt;A. 自動解決後の確認を怠らない&lt;/h3&gt;
&lt;p&gt;rerereがコンフリクトを自動で解決した後でも、そのファイルはステージングされた状態で停止する。これは、Gitがユーザーに最終確認を促しているためである。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;必須の操作&lt;/strong&gt;: rerereが自動解決を行った際は、必ず以下の手順を踏むこと。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git status&lt;/code&gt;や&lt;code&gt;git diff&lt;/code&gt;で自動解決の内容を確認する。&lt;/li&gt;
&lt;li&gt;単体テストや統合テストを実行し、解決後のコードが意図通りに動作することを確認する。&lt;/li&gt;
&lt;li&gt;問題なければ、&lt;code&gt;git commit&lt;/code&gt;または&lt;code&gt;git rebase --continue&lt;/code&gt;などで作業を完了する。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;b-誤った解決の削除&quot;&gt;B. 誤った解決の削除&lt;/h3&gt;
&lt;p&gt;もし、過去に誤った解決方法をrerereに記録させてしまった場合、次回同じコンフリクトに遭遇したときに間違った解決が自動で適用されてしまう。その場合は、&lt;code&gt;forget&lt;/code&gt;サブコマンドを使って記録を削除し、手動で正しい解決をやり直すこと。&lt;/p&gt;
&lt;p&gt;特定のファイルの記録を削除:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# 現在のコンフリクト中のファイル（例: src/file.js）の記録を削除&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; rerere&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; forget&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; src/file.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;c-状態確認用のサブコマンド&quot;&gt;C. 状態確認用のサブコマンド&lt;/h3&gt;
&lt;p&gt;rerereは通常、自動で動作するが、以下のコマンドで現在の動作状況を確認できる。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git rerere status&lt;/code&gt;: 現在のコンフリクト処理において、rerereが関与しているファイルを表示する。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git rerere diff&lt;/code&gt;: rerereが現在適用しようとしている（または適用した）解決策の差分を表示し、手動での確認を助ける。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Async Python: The Different Forms of Concurrency</title><link>https://blog.kj-dev.net/posts/l/2025/10/python-concurrency-basics/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/10/python-concurrency-basics/</guid><pubDate>Sun, 05 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://masnun.rocks/2016/10/06/async-python-the-different-forms-of-concurrency/&quot;&gt;Async Python: The Different Forms of Concurrency&lt;/a&gt;, Abu Ashraf Masnun&lt;/p&gt;
&lt;p&gt;Pythonでパフォーマンスチューニングや非同期処理について学ぶ際、必ずと言っていいほど登場するのが「非同期」「並行」「並列」といった言葉だ。
これらの言葉の定義に触れつつ、Pythonにおける非同期処理について解説した良い記事。&lt;/p&gt;</content:encoded></item><item><title>Python並行処理: yt-dlpでの動画ダウンロードを高速化する</title><link>https://blog.kj-dev.net/posts/python-concurrency-yt-dlp/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/python-concurrency-yt-dlp/</guid><description>Pythonにおける並行処理と動画ダウンロードの高速化</description><pubDate>Sat, 04 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Pythonの動画ダウンロードライブラリ&lt;a href=&quot;https://github.com/yt-dlp/yt-dlp&quot;&gt;yt-dlp&lt;/a&gt;を使って複数の動画をダウンロードする際、単純にForループで順番に処理すると時間がかかってしまう。
例えば、次のコードは複数のURLから動画をダウンロードするが、1つずつ順番に処理するため、全体の時間が長くなってしまう。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; yt_dlp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;urls &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;https://www.youtube.com/watch?v=...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;https://www.youtube.com/watch?v=...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;https://www.youtube.com/watch?v=...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#82AAFF&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; yt_dlp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;YoutubeDL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;get_options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;file_path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; ydl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; url &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; urls&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;        ydl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;download&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;動画を1つずつ順番にダウンロードするのではなく、並行処理にすることによって全体の時間を短縮したい。&lt;/p&gt;
&lt;h2 id=&quot;gilとタスクの性質&quot;&gt;GILとタスクの性質&lt;/h2&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;!注意!&lt;/em&gt; Python 3.13以降では、実験的に&lt;a href=&quot;https://docs.python.org/3/whatsnew/3.13.html#free-threaded-cpython&quot;&gt;GILを無効化したバージョン&lt;/a&gt;が提供されており、今後GILと並行処理をめぐる状況は大きく変わる可能性がある。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Pythonの並行処理を理解する上で避けて通れないのが、&lt;strong&gt;GIL（Global Interpreter Lock）&lt;/strong&gt; の存在だ。&lt;/p&gt;
&lt;p&gt;GILは、Pythonのバイトコードを一度に1つのスレッドでしか実行できないようにするロック機構である。GILの存在により、ある瞬間にPythonのコードを実行できるのは常に1つのスレッドだけに限られる。&lt;/p&gt;
&lt;p&gt;GILの挙動を理解するため、タスクの性質を次の2つに分類する。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;I/Oバウンド&lt;/strong&gt;: ファイルの読み書きやネットワーク通信など、I/Oの待ち時間がボトルネックになるタスク（動画のダウンロードはこちらに該当する）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPUバウンド&lt;/strong&gt;: 複雑な計算など、CPUの処理能力がボトルネックになるタスク。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I/O待機中にはGILが解放されるため、その間に別のI/O操作を進めることができる。したがって、&lt;em&gt;I/Oバウンドなタスクは、複数スレッドへの分散が効果的だ。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;一方、CPUバウンドなタスクでは、GILが効いてしまい、複数スレッドを使っても同時にPythonコードを実行できない。そのため、GILによるロックを回避するには複数プロセスを立ち上げる必要がある。つまり、&lt;em&gt;CPUバウンドなタスクは、複数プロセスへの分散が効果的だ。&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;並行処理アプローチ&quot;&gt;並行処理アプローチ&lt;/h2&gt;
&lt;p&gt;GILの特性とタスクの性質を踏まえると、Pythonの並行処理には複数のアプローチがある。どのアプローチを選ぶべきか、以下のフローチャートを参考に判断できる。&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/python-concurrency-dicision-tree.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;並行処理のフローチャート&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;!--
diargram:
https://www.mermaidchart.com/app/projects/44dcf890-1b53-46d6-8d60-761cd1893278/diagrams/3ab2acdc-7de9-4e06-875c-bbe46aa21bce/version/v0.1/edit
--&gt;
&lt;h4 id=&quot;1-multiprocessing-cpuバウンドタスク向け&quot;&gt;1. &lt;code&gt;multiprocessing&lt;/code&gt;: CPUバウンドタスク向け&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;multiprocessing&lt;/code&gt;は、複数のプロセスを立ち上げ、各プロセスで独立してPythonコードを実行するライブラリだ。CPUバウンドなタスクに効果的だが、プロセス間の通信にオーバーヘッドがあるため、I/Oバウンドなタスクにはあまり向いていない。&lt;/p&gt;
&lt;h4 id=&quot;2-threading-ioバウンドタスク向け&quot;&gt;2. &lt;code&gt;threading&lt;/code&gt;: I/Oバウンドタスク向け&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;threading&lt;/code&gt;は、スレッドを使って並行処理を実現するライブラリだ。I/O待機中にGILが解放され、他のスレッドが処理を進められるため、I/Oバウンドなタスクに非常に効果的だ。ただし、前述の通りGILの存在により、CPUバウンドなタスクには向いていない。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;multiprocessing&lt;/code&gt;と&lt;code&gt;threading&lt;/code&gt;には、より高水準なAPIである&lt;code&gt;concurrent.futures&lt;/code&gt;モジュールが存在し、こちらを使うと並行処理をより簡単に実装できる。&lt;/p&gt;&lt;/blockquote&gt;
&lt;h4 id=&quot;3-asyncio-ioバウンドタスク向けの現代的な方法&quot;&gt;3. &lt;code&gt;asyncio&lt;/code&gt;: I/Oバウンドタスク向けの現代的な方法&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;asyncio&lt;/code&gt;は、Pythonの標準ライブラリで提供される非同期I/Oフレームワークだ。&lt;/p&gt;
&lt;p&gt;単一スレッド内のイベントループという仕組みを使い、&lt;code&gt;await&lt;/code&gt;キーワードでI/O処理の完了を非同期に待ちながら、その間に他の処理を進めることができる。スレッドと同様にI/Oバウンドなタスクに非常に効果的で、&lt;code&gt;threading&lt;/code&gt;よりもさらに軽量に多くの処理を扱える場合がある。&lt;/p&gt;
&lt;p&gt;ただし、&lt;code&gt;asyncio&lt;/code&gt;に対応した関数でなければ、この方法で並行処理を行うことはできない。&lt;code&gt;yt-dlp&lt;/code&gt;は&lt;code&gt;asyncio&lt;/code&gt;に対応していないため、そのまま&lt;code&gt;await&lt;/code&gt;を使ってもイベントループがブロックされてしまい、並行処理の効果が得られず、同期的なコードと同じ結果になる。&lt;/p&gt;
&lt;p&gt;このような場合は&lt;code&gt;asyncio.to_thread&lt;/code&gt;を使うことで、同期的な関数を別スレッドで実行し、その完了を非同期に待つことができる。これにより、&lt;code&gt;asyncio&lt;/code&gt;のイベントループをブロックすることなく、同期的なI/Oバウンドタスクを並行化できる（この場合、内部でスレッドを生成しているため、実質的には&lt;code&gt;threading&lt;/code&gt;と同様の効果が得られる）。&lt;/p&gt;
&lt;h3 id=&quot;参考資料&quot;&gt;参考資料&lt;/h3&gt;
&lt;p&gt;ここまでで紹介した概念についてより深く知りたい場合は、以下の資料が非常に参考になる。&lt;/p&gt;
&lt;p&gt;GILについて:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.dabeaz.com/python/UnderstandingGIL.pdf&quot;&gt;Understanding the Python GIL&lt;/a&gt;, David Beazley&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=AZnGRKFUU0c&quot;&gt;threading vs multiprocessing in python&lt;/a&gt;, Dave’s Space&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;asyncioについて:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://peps.python.org/pep-0492/&quot;&gt;PEP492&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Y4Gt3Xjd7G8&amp;#x26;list=WL&amp;#x26;index=21&quot;&gt;Build Your Own Async&lt;/a&gt;, David Beazley&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;yt-dlpを並行化する&quot;&gt;yt-dlpを並行化する&lt;/h2&gt;
&lt;p&gt;それでは、実際のコードで&lt;code&gt;yt-dlp&lt;/code&gt;を使った動画ダウンロード処理の並行化を試してみよう。&lt;/p&gt;
&lt;p&gt;フローチャートに従うと、まず&lt;code&gt;yt-dlp&lt;/code&gt;による動画ダウンロードはI/Oバウンドなタスクである。
そして、&lt;code&gt;yt-dlp&lt;/code&gt;は&lt;code&gt;asyncio&lt;/code&gt;には対応していない。&lt;/p&gt;
&lt;p&gt;そのため、次のように&lt;code&gt;yt-dlp&lt;/code&gt;の&lt;code&gt;download&lt;/code&gt;メソッドを直接&lt;code&gt;await&lt;/code&gt;しようとしても、処理自体は同期的に実行されてしまい、高速化の効果は得られない。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; async_download_video_thread&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt;video_id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#C5E478&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt; file_path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; Path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;    with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; yt_dlp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;YoutubeDL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;get_options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;file_path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; ydl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;        # NG: イベントループがブロックされる&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;        await&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; ydl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;download&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;video_id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;実質的に冒頭の同期的なコードと同じで、並行化の効果は得られない。&lt;/p&gt;
&lt;p&gt;そこで、フローチャートに従い、&lt;code&gt;threading&lt;/code&gt;の利用を検討する。より簡潔に書ける&lt;code&gt;concurrent.futures&lt;/code&gt;を使うと、次のようになる。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; concurrent&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;futures &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; ThreadPoolExecutor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; download_video_thread&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt;video_ids&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; list&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#C5E478&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;],&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt; file_path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; Path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt; max_workers&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#C5E478&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; download&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt;video_id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; yt_dlp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;YoutubeDL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;get_options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;file_path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; ydl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;            ydl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;download&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;video_id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;    with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; ThreadPoolExecutor&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D7DBE0&quot;&gt;max_workers&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;max_workers&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; executor&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;        executor&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;download&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt; video_ids&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;もう一つの方法として、&lt;code&gt;asyncio.to_thread&lt;/code&gt;の利用がある。これは、同期的な関数を別スレッドで実行し、その完了を非同期に待つことができる関数だ。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; async_download_video_thread&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt;video_id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#C5E478&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt; file_path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; Path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;    with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; yt_dlp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;YoutubeDL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;get_options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;file_path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; ydl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;        # 同期的なdownloadメソッドを別スレッドで実行し、完了を待つ&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;        await&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; asyncio&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;to_thread&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;ydl.download&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;video_id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;この方法は&lt;code&gt;asyncio&lt;/code&gt;のイベントループをブロックしないため、他の非同期処理と組み合わせる際に有効だ。内部的には&lt;code&gt;threading&lt;/code&gt;と同様、複数のスレッドでダウンロード処理を並行化している。&lt;/p&gt;
&lt;h2 id=&quot;パフォーマンス比較&quot;&gt;パフォーマンス比較&lt;/h2&gt;
&lt;p&gt;ここまで紹介した3つのアプローチと、従来の同期的な方法について、実際に動画ダウンロードのパフォーマンスを比較した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;タスク&lt;/strong&gt;: &lt;a href=&quot;https://www.youtube.com/watch?v=v9Qiwzgkxhw&quot;&gt;動画&lt;/a&gt;を3回ダウンロード
&lt;ul&gt;
&lt;li&gt;動画：最低画質、音声なし（&lt;strong&gt;608KB&lt;/strong&gt;）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;スレッド数&lt;/strong&gt;: 3&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python&lt;/strong&gt;: 3.13&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;次の4つのアプローチを試した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1. sync&lt;/code&gt;: 通常の同期処理&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2. async&lt;/code&gt;: asyncioでそのままyt-dlpを呼び出す(実質的に同期処理と同じ)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;3. thread&lt;/code&gt;: &lt;code&gt;concurrent.futures&lt;/code&gt;を使い、複数スレッドでyt-dlpを呼び出す&lt;/li&gt;
&lt;li&gt;&lt;code&gt;4. async-thread&lt;/code&gt;: asyncioでスレッドを利用してyt-dlpを呼び出す&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;実際のコードは&lt;a href=&quot;https://gist.github.com/kj-9/03130d29292660d1a2cc4b74589ea133&quot;&gt;gist&lt;/a&gt;に、パフォーマンス比較には&lt;a href=&quot;https://github.com/sharkdp/hyperfine&quot;&gt;hyperfine&lt;/a&gt;を利用している。&lt;/p&gt;
&lt;p&gt;結果を次のグラフに示す。&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;425&quot; seamless frameborder=&quot;0&quot; scrolling=&quot;yes&quot; src=&quot;https://docs.google.com/spreadsheets/d/e/2PACX-1vSDbjHCCqoBApp2g30Ur3E9ZdbLaswg3xd7s2uCSHatyzI_PB3i-nkx_vLmlN9trdkEHl0bIhnlqses/pubchart?oid=982355311&amp;#x26;format=image&quot;&gt;&lt;/iframe&gt;
&lt;ul&gt;
&lt;li&gt;同期処理（&lt;code&gt;sync&lt;/code&gt;）では約12秒かかった。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;async&lt;/code&gt;は&lt;code&gt;yt-dlp&lt;/code&gt;が&lt;code&gt;asyncio&lt;/code&gt;に対応していないため、同期処理と同じ約12秒かかった。&lt;/li&gt;
&lt;li&gt;スレッドを使った2つの方法（&lt;code&gt;thread&lt;/code&gt;, &lt;code&gt;async-thread&lt;/code&gt;）は、いずれも約6秒という結果になった。
&lt;ul&gt;
&lt;li&gt;スレッドの利用により、ダウンロード速度が約2倍に向上したことがわかる。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;yt-dlp&lt;/code&gt;のような同期的（ブロッキング）なI/Oバウンドタスクを並行化するには、スレッドを利用する方法が有効だ。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;asyncio&lt;/code&gt;を主に使う場合は、&lt;code&gt;asyncio.to_thread&lt;/code&gt;を利用することで、イベントループをブロックせずに同期処理を別スレッドに委譲できる。これは実質的に&lt;code&gt;threading&lt;/code&gt;と同様の効果だが、他の非同期処理と組み合わせる際にコードの統一性を保てるという利点がある。&lt;/p&gt;
&lt;p&gt;将来&lt;code&gt;yt-dlp&lt;/code&gt;自体が&lt;code&gt;async/await&lt;/code&gt;に対応すれば、&lt;code&gt;asyncio.to_thread&lt;/code&gt;を使わずに、より効率的な非同期処理が実現できるだろう。&lt;/p&gt;</content:encoded></item><item><title>Githubで手動でサブスクライブしたIssueとPRの一覧を見る方法</title><link>https://blog.kj-dev.net/posts/l/2025/09/list-subscribed-issue-and-prs/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/09/list-subscribed-issue-and-prs/</guid><pubDate>Sun, 28 Sep 2025 17:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://github.com/notifications/subscriptions?reason=manual&quot;&gt;サブスクリプションの一覧&lt;/a&gt;から確認できる。&lt;/p&gt;
&lt;p&gt;filterのサーチクエリはサブスクリプションの検索には対応していない。
&lt;a href=&quot;https://stackoverflow.com/questions/64435858/how-to-search-github-issues-for-the-ones-youre-watching?utm_source=chatgpt.com&quot;&gt;こちら&lt;/a&gt;のStackoverflowも参考になる。&lt;/p&gt;</content:encoded></item><item><title>ハッカーニュースの日本語要約RSSフィードを作った</title><link>https://blog.kj-dev.net/posts/hacker-news-rss/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/hacker-news-rss/</guid><description>Hacker Newsの日本語要約をRSSフィードで読む</description><pubDate>Wed, 16 Apr 2025 23:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hacker Newsが結構好きなのだが、英語の情報がほとんどのため、内容を把握するのにいつも時間がかかる。&lt;/p&gt;
&lt;p&gt;Catnoseさんの&lt;a href=&quot;https://catnose.me/lab/hackernews-ja/&quot;&gt;Hacker Newsの日本語要約ページ&lt;/a&gt;がとても便利で、いつもお世話になっている。だが、RSSフィードは提供されてないので、RSSリーダーで読むことができない。&lt;/p&gt;
&lt;p&gt;自分は&lt;a href=&quot;https://feedly.com/&quot;&gt;Feedly&lt;/a&gt;を使ってRSSフィードをチェックしているので、Hacker Newsの日本語要約をRSSフィードで読みたいと思った。&lt;/p&gt;
&lt;p&gt;そこで、Hacker Newsの日本語要約のRSSフィードを自分で作ってみた。&lt;/p&gt;
&lt;h2 id=&quot;rssフィード&quot;&gt;RSSフィード&lt;/h2&gt;
&lt;p&gt;さっそくだが&lt;a href=&quot;https://kj-9.github.io/hacker-news-ja-summary-rss/rss.xml&quot;&gt;こちら&lt;/a&gt;がRSSフィードのURLだ。&lt;/p&gt;
&lt;p&gt;その日のHacker NewsのスレッドTop10の、日本語での要約をRSSフィードで配信している。&lt;/p&gt;
&lt;h3 id=&quot;実装&quot;&gt;実装&lt;/h3&gt;
&lt;p&gt;RSSはGithub Pagesでホスティングしている。レポジトリは&lt;a href=&quot;https://github.com/kj-9/hacker-news-ja-summary-rss&quot;&gt;こちら&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;RSSの更新には、Github Actionsを使っている。
Pythonスクリプトを実行しHacker Newsの日本語要約を取得し、Geminiで要約し、RSSフィードのXMLを生成といった流れだ。&lt;/p&gt;
&lt;p&gt;実装にはSimon Wllison氏の&lt;a href=&quot;https://simonwillison.net/2025/Apr/8/llm-hacker-news/&quot;&gt;llm-hacker-news&lt;/a&gt;を利用した。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://llm.datasette.io/en/stable/&quot;&gt;LLM&lt;/a&gt;というCLIツールのプラグインで、簡単にHacker Newsのスレッドを取得し、geminiなどのモデルに投入できる:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;llm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --fragment&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;hn:43669185&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --system&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;日本語で要約して&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --model&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; gemini-2.0-flash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;--fragment &apos;hn:{スレッドID}&apos;&lt;/code&gt; で指定したHacker Newsのスレッドをプロンプトに流すことができる。&lt;/p&gt;
&lt;p&gt;LLMではPython APIも利用可のだが、執筆時点ではまだllm-hacker-newsなど&lt;code&gt;--fragments&lt;/code&gt;で利用するPluginがサポートされていないようだった。これについては&lt;a href=&quot;https://github.com/simonw/llm/issues/914&quot;&gt;Issue&lt;/a&gt;をファイルしている。&lt;/p&gt;
&lt;h2 id=&quot;rssフィードの簡易リーダー&quot;&gt;RSSフィードの簡易リーダー&lt;/h2&gt;
&lt;p&gt;作成してFeedlyで読み込んでみて気づいたのだが、Feedlyはすぐに更新を反映してくれない。
そのため、RSSフィードを更新しても、Feedlyで反映されるまで時間がかかる。&lt;/p&gt;
&lt;p&gt;それがちょっと不満だったので、Claude3.7とGithub CopilotでVibe Codingして簡易なRSSリーダーを作成した。&lt;/p&gt;
&lt;p&gt;ロードしたRSSと閲覧中のエントリをURLをシェアできるように作ってもらった。例えば以下のリンクから、Hacker Newsの日本語要約の、4Chanの情報漏洩についてのエントリが閲覧できる:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kj-9.github.io/tools/rss-reader.html?feed=https%253A%252F%252Fkj-9.github.io%252Fhacker-news-ja-summary-rss%252Frss.xml&amp;#x26;entry=43691334&quot;&gt;https://kj-9.github.io/tools/rss-reader.html?feed=https%253A%252F%252Fkj-9.github.io%252Fhacker-news-ja-summary-rss%252Frss.xml&amp;#x26;entry=43691334&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/rss-reader-vibe-coded.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;VibeCodeした簡易なRSSリーダー&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;中身は単一の静的HTMLファイルで、こちらもGithub Pagesでホスティングしている。&lt;/p&gt;
&lt;p&gt;URLシェアできるとはいっても、クライアントサイドのJavascriptのみで動作しているので、Javascriptが動作しない環境では利用できない。&lt;/p&gt;</content:encoded></item><item><title>Quoting &quot;Simon Willison: My career in side projects and open source&quot; video on YouTube</title><link>https://blog.kj-dev.net/posts/l/2025/04/quoting-simonw/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/04/quoting-simonw/</guid><pubDate>Sun, 13 Apr 2025 18:00:00 GMT</pubDate><content:encoded>&lt;p&gt;on &lt;a href=&quot;https://youtu.be/wqjye4QnWK0?feature=shared&quot;&gt;Youtube&lt;/a&gt; by &lt;a href=&quot;https://simonwillison.net/about/&quot;&gt;Simon Willison&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Simon Willison氏が自身のキャリアについて語ったビデオを見つけた。
2019/12/9に行われたトークなので、少々時間が立っているが、とても興味深い内容だった。&lt;/p&gt;
&lt;p&gt;いくつか印象的だった部分を引用してみる。&lt;/p&gt;
&lt;h3 id=&quot;0010&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=wqjye4QnWK0&amp;#x26;t=10s&quot;&gt;00:10~&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;基本的に、私はサイドプロジェクトやオープンソース関連のことを20年ほど続けてきました。最近気づいたのですが、私のキャリアにおける重要な転機はすべて、サイドプロジェクトとして始まったものだったのです。&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&quot;5239&quot;&gt;&lt;a href=&quot;https://youtu.be/wqjye4QnWK0?t=3159&quot;&gt;52:39~&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;部分的には、私が持っている大きなチートは、基本的に、構築するのが本当に簡単だとわかっているプロジェクトにしか取り組まないことです。&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;それが速いとわかっています。基本的には過去20年間、使える小さなトリック、チートシートのようなものを蓄積してきました。そして、時々、何かが現れて、「これとこれを過去に構築したから、そしてこれとこれのおかげで、これは数日でできるプロジェクトで、ローンチできる」と考えます。&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;正直なところ、何かを公開できるまでに1週間以上かかるプロジェクトには取り組みません。私が書くプラグインのほとんどは数時間で、その後、最初のリリースを公開します。それは私が学んだことです…つまり、「早くリリースし、頻繁にリリースする」ということです。それがサイドプロジェクトにとって非常に重要であることがわかりました。なぜなら、代替案は、サイドプロジェクトを決して出荷しないことです。&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&quot;5556&quot;&gt;&lt;a href=&quot;https://youtu.be/wqjye4QnWK0?t=3356&quot;&gt;55:56~&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;実際、それはDataset自体に関する私の哲学です。何かを行うのに必要な労力の量を、例えば1週間かかるものを、数時間に短縮するツールやテクノロジーには、本当に興味深い何かがあると思います。&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;もしあなたが新聞社で、地元の老人ホームに関するデータを公開したいとして、JSONエクスポートなどのウェブインターフェースを立ち上げるためにエンジニアに1週間作業してもらう必要があるなら、それはやらないでしょう。そのために1週間のエンジニアリング時間を割く余裕はありません。&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;しかし、もしDatasetがそれを数時間に短縮するなら、あなたはそれをやるでしょう。ですから、この種の活性化エネルギーがあり、それを行うのに十分な時間がかかるために選択しないであろう何かを取り、それをバーの下に落とし、そしてそれをやらせるツールやテクニックがあります。そして、私はそのようなものが大好きです。私にとって、もし将来、時間がかかりすぎるためにやらなかったであろうダース以上のプロジェクトを行うことができるツールを構築できれば、それは非常に価値があります。&lt;/p&gt;&lt;/blockquote&gt;</content:encoded></item><item><title>AnyIO: Prefectの非同期処理ライブラリ</title><link>https://blog.kj-dev.net/posts/l/2025/04/anyio/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/04/anyio/</guid><pubDate>Thu, 03 Apr 2025 00:30:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://www.prefect.io/&quot;&gt;prefect&lt;/a&gt;のブログで、AnyIOが紹介されている。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.prefect.io/blog/oss-love-letters-how-anyio-powers-prefects-async-architecture&quot;&gt;How AnyIO powers Prefect’s Async Architecture&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;prefectの内部的な非同期処理では、AnyIOが積極的に使われているようだ。AnyIOについて少し調べてみたので、メモしておく。&lt;/p&gt;
&lt;h3 id=&quot;anyio&quot;&gt;AnyIO&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://anyio.readthedocs.io/en/stable/&quot;&gt;AnyIO&lt;/a&gt;は非同期処理を行うためのPythonライブラリ。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;AnyIO is an asynchronous networking and concurrency library that works on top of either asyncio or trio. It implements trio-like structured concurrency (SC) on top of asyncio and works in harmony with the native SC of trio itself.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;最近ようやくPythonの非同期処理の標準ライブラリであるasyncioを触りだしたが、いろいろと足りていないと感じる部分も多い。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://trio.readthedocs.io/en/stable/&quot;&gt;trio&lt;/a&gt;はそんな部分を補うために作られたOSSライブラリだ。&lt;/p&gt;
&lt;p&gt;一方でAnyIOのドキュメントと冒頭のブログによると、AnyIOは、asyncioとtrioの両方と互換性を持たせつつ、より統合されたAPIを提供することを目指している。&lt;/p&gt;
&lt;p&gt;AnyIOは&lt;a href=&quot;https://github.com/agronholm&quot;&gt;Alex Grönholm&lt;/a&gt;という方がメインのメンテナーをしている。Pythonの非同期処理界隈では有名な方のようだ。&lt;/p&gt;
&lt;p&gt;この手のライブラリはコアチームにメンテされていくのが理想的だ。だがAnyIOにはasyncioやtrioそれぞれの開発者がAnyIOにコントリビュートしているらしく、継続性について一つの安心材料になると感じている。&lt;/p&gt;
&lt;h3 id=&quot;anyioの特徴&quot;&gt;AnyIOの特徴&lt;/h3&gt;
&lt;p&gt;asyncioでは非同期のファイル処理やネットワーク処理を簡潔に行うための関数やAPIが提供されていない。&lt;/p&gt;
&lt;p&gt;そのため、ファイル処理では&lt;a href=&quot;https://github.com/Tinche/aiofiles&quot;&gt;aiofile&lt;/a&gt;、ネットワーク処理では&lt;a href=&quot;https://www.python-httpx.org/&quot;&gt;httpx&lt;/a&gt;や&lt;a href=&quot;https://docs.aiohttp.org/en/stable/&quot;&gt;aiohttp&lt;/a&gt;などのライブラリを利用することが多い。&lt;/p&gt;
&lt;p&gt;AnyIOでは、非同期のファイル処理や高水準なネットワーク処理を行うためのAPIを提供している。詳細な比較はできてないが、aiofileやaiohttpなどのライブラリをカバーすることができそうだ。&lt;/p&gt;
&lt;p&gt;また、スレッドやプロセスも扱えるし、タスクをグループ化し、きめ細かいキャンセル処理を行うことができる。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;AnyIO offers the following functionality:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Task groups (&lt;a href=&quot;https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning&quot;&gt;nurseries&lt;/a&gt; in trio terminology)&lt;/li&gt;
&lt;li&gt;High-level networking (TCP, UDP and UNIX sockets)
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Happy_Eyeballs&quot;&gt;Happy eyeballs&lt;/a&gt; algorithm for TCP connections (more robust than that of asyncio on Python 3.8)&lt;/li&gt;
&lt;li&gt;async/await style UDP sockets (unlike asyncio where you still have to use Transports and Protocols)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A versatile API for byte streams and object streams&lt;/li&gt;
&lt;li&gt;Inter-task synchronization and communication (locks, conditions, events, semaphores, object streams)&lt;/li&gt;
&lt;li&gt;Worker threads&lt;/li&gt;
&lt;li&gt;Subprocesses&lt;/li&gt;
&lt;li&gt;Asynchronous file I/O (using worker threads)&lt;/li&gt;
&lt;li&gt;Signal handling&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;AnyIOが依存するパッケージもミニマムなものだ。
pyproject.tomlの&lt;a href=&quot;https://github.com/agronholm/anyio/blob/2a63fd0bef1575e583c4cf63cebe7d76a218c83e/pyproject.toml#L28-L33&quot;&gt;dependencies&lt;/a&gt;を見てみると、以下のようなものがある。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;toml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;dependencies&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;exceptiongroup &gt;= 1.0.2; python_version &amp;#x3C; &apos;3.11&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;idna &gt;= 2.8&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;sniffio &gt;= 1.1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;typing_extensions &gt;= 4.5; python_version &amp;#x3C; &apos;3.13&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以下は比較的小さなPythonライブラリだ:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://pypi.org/project/idna/&quot;&gt;idna&lt;/a&gt;: 国際化ドメイン名（IDN）を処理するためのライブラリ&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pypi.org/project/sniffio/&quot;&gt;sniffio&lt;/a&gt;: 現在実行中の非同期フレームワークを検出するためのライブラリ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;その他は、あくまでPythonの標準ライブラリを拡張するためのもので、Pythonのバージョンが進めば不要になるものだ。&lt;/p&gt;
&lt;p&gt;どれも軽量な依存関係で、AnyIOはPure Pythonに近い状態で書かれている、と言えるだろう。&lt;/p&gt;
&lt;p&gt;このように、AnyIOはシンプルかつ高機能な非同期処理ライブラリであり、今後自分のプロジェクトでも使ってみたいと思った。&lt;/p&gt;
&lt;h3 id=&quot;補足-ファイルの非同期処理について&quot;&gt;補足: ファイルの非同期処理について&lt;/h3&gt;
&lt;p&gt;asyncioにおける、非同期なファイルIOのサポートについて、StackOverflowが参考になった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/34699948/does-asyncio-supports-asynchronous-i-o-for-file-operations&quot;&gt;Does asyncio supports asynchronous I/O for file operations?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;次のことが言及されている:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;asyncioではファイルIOは直接的にはサポートしていない&lt;/li&gt;
&lt;li&gt;そもそも、多くのOSでは、OSレベルで非同期なファイルIOをサポートしていない
&lt;ul&gt;
&lt;li&gt;Linuxの最近のバージョン(&gt;=4.18?)や、Windowsはサポートしている模様&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Node.jsの非同期ファイルAPIも、内部的にはスレッドを使っている&lt;/li&gt;
&lt;li&gt;aiofileも、内部的にはスレッドを使っている&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;そのほか、OSの非同期ファイルIOについては、次の記事も参考になった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.libtorrent.org/2012/10/asynchronous-disk-io/&quot;&gt;asynchronous disk I/O&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Quoting Pekka Enberg</title><link>https://blog.kj-dev.net/posts/l/2025/04/quoting-penberg/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/04/quoting-penberg/</guid><pubDate>Tue, 01 Apr 2025 23:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;&lt;p&gt;Senior developer don’t want to rewrite legacy code because it’s insanely hard. That’s why we need fearless 25 year olds who don’t know better to do it to move forward.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;on &lt;a href=&quot;https://x.com/penberg/status/1905971121863684125&quot;&gt;X&lt;/a&gt; by &lt;a href=&quot;https://penberg.org/&quot;&gt;Pekka Enberg&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Airflow 3.0 Betaをローカルで動かしてみる</title><link>https://blog.kj-dev.net/posts/l/2025/03/try-airflow-v30-beta/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/03/try-airflow-v30-beta/</guid><description>uvとAirflow BreezeでBetaバージョンを起動</description><pubDate>Thu, 27 Mar 2025 22:45:00 GMT</pubDate><content:encoded>&lt;p&gt;Airflow 3.0が現在開発中となっている。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=308153069#Airflow3.0-Timelines&quot;&gt;開発タイムライン&lt;/a&gt;によると、3月末にはRCがリリースされる予定だ。&lt;/p&gt;
&lt;p&gt;v3.0の主な変更点については、Astronomerが提供する情報が詳しい:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.astronomer.io/airflow/3-0/&quot;&gt;Airflow 3.0 is coming.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.astronomer.io/blog/apache-airflow-3-development-update/&quot;&gt;Apache Airflow® 3 Development Update&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;執筆時点でBeta4がリリースされているので、ローカルで試してみる。&lt;/p&gt;
&lt;h2 id=&quot;airflow-30-betaをローカルで動かす&quot;&gt;Airflow 3.0 Betaをローカルで動かす&lt;/h2&gt;
&lt;p&gt;BetaリリースはGitHubのリポジトリ上のタグとして管理されているようだ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/apache/airflow/tree/3.0.0b4&quot;&gt;v3.0b4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PyPIやGitHubリリースは作成されていないようだ。&lt;/p&gt;
&lt;p&gt;まずはタグを指定してリポジトリをCloneする。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; clone&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --depth&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --branch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;3.0.0b4&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; https://github.com/apache/airflow.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; airflow&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;uvを使ってBreezeをインストールする。
BreezeのインストールにはDockerが必要となる。詳細は&lt;a href=&quot;https://github.com/apache/airflow/blob/main/dev/breeze/doc/01_installation.rst#installation&quot;&gt;GitHub上のドキュメント&lt;/a&gt;に記載されている。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;uv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; ./dev/breeze&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Airflow起動時にpre-commitがないとエラーが出たので、pre-commitをインストールしておく。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;uv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; pre-commit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Breezeを使ってAirflowを起動する。初めて実行する際は、コンテナのセットアップなどで時間がかかる。
&lt;code&gt;--load-example-dags&lt;/code&gt;をつけるとExample DAGsがロードされる。起動するだけだとDAGが存在しないので、つけておくと良い。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;breeze&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; start-airflow&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --load-example-dags&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完了すると、Tmuxセッションが立ち上がり、Airflowが起動する。&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/airflow-breeze-terminal.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;airflow-breeze-terminal&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;それぞれのPaneで、Triggerer, Scheduler, API Server, DAG Processorが起動している。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://localhost:8080/&lt;/code&gt;にアクセスすると、AirflowのUIが表示される。&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/airflow-v3.0-beta4-ui.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;airflow-v3.0-beta4-ui&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;v3.0のUIを確認することができた。v2と比べて、UIが大きく変わっている。&lt;/p&gt;
&lt;p&gt;Airflowを終了するには、Tmuxの左上のセッションで&lt;code&gt;stop_airflow&lt;/code&gt;と入力する。&lt;/p&gt;</content:encoded></item><item><title>terraformはS3-nativeなstate lockをどのように実装しているのか</title><link>https://blog.kj-dev.net/posts/l/2025/03/how-terraform-implement-state-lock-in-s3/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/03/how-terraform-implement-state-lock-in-s3/</guid><pubDate>Wed, 26 Mar 2025 23:30:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://github.com/hashicorp/terraform/releases/tag/v1.11.0&quot;&gt;terraform v1.11.0&lt;/a&gt;でS3-nativeなstate lockが実装された。
これによって、今まではDynamoDBが必要だったstate lockをS3だけで実現できるようになった。&lt;/p&gt;
&lt;p&gt;ベースとなる実装は&lt;a href=&quot;https://github.com/hashicorp/terraform/pull/35661&quot;&gt;こちらのPR&lt;/a&gt;で実装されている。&lt;/p&gt;
&lt;h2 id=&quot;s3-conditional-writes&quot;&gt;S3 Conditional Writes&lt;/h2&gt;
&lt;p&gt;PRのDescriptionによると、S3で&lt;a href=&quot;https://aws.amazon.com/jp/about-aws/whats-new/2024/08/amazon-s3-conditional-writes/&quot;&gt;conditional writes&lt;/a&gt;(条件付き書き込み)がサポートされたことで、この実装が可能になったとのこと。&lt;/p&gt;
&lt;p&gt;conditional writesとは何かというと、「あるファイルをS3に書き込む際に、そのファイルが既に存在している場合は書き込みを防ぐことができる」というもの。&lt;/p&gt;
&lt;p&gt;PutObjectリクエストに&lt;code&gt;&apos;If-None-Match&apos;: &apos;*&apos;&lt;/code&gt;ヘッダーを追加することで、conditional writesを利用できる。(&lt;a href=&quot;https://arc.net/l/quote/pikbwyis&quot;&gt;詳細&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;そんな単純なものが今までサポートされてなかったのか？
そしてそんな単純なものがサポートされて何が嬉しいのか？&lt;/p&gt;
&lt;p&gt;という気持ちになるのだが、これが複数クライアントの競合Lockを実装するのに必要な機能だった。&lt;/p&gt;
&lt;h2 id=&quot;terraformのs3-nativeなstate-lockの仕組み&quot;&gt;TerraformのS3-nativeなstate lockの仕組み&lt;/h2&gt;
&lt;p&gt;次の仕組みで、S3-nativeなstate lockが実現されている。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ロックの動作&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Terraformの操作（plan、apply等）を開始すると、まずS3バケットに&lt;code&gt;.tflock&lt;/code&gt;ファイルをconditinal writesで作成を試みる&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.tflock&lt;/code&gt;ファイル作成に成功した場合:
&lt;ul&gt;
&lt;li&gt;ロックの取得に成功したと判断し、操作を続行&lt;/li&gt;
&lt;li&gt;Terraformの操作完了後、&lt;code&gt;.tflock&lt;/code&gt;ファイルを削除&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.tflock&lt;/code&gt;ファイル作成に失敗した場合:
&lt;ul&gt;
&lt;li&gt;他のユーザーが操作中と判断し、エラーを返す&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;conditinal writesでただファイルを書き込むだけで、他のユーザーが操作中かどうかを判断できるのがとてもシンプル。&lt;/p&gt;
&lt;h2 id=&quot;gcsのstate-lockはどのようになっているのか&quot;&gt;GCSのstate lockはどのようになっているのか&lt;/h2&gt;
&lt;p&gt;GCSはconditional writesに相当する機能が、以前からサポートされている。
仕組み自体は上記のS3-nativeなstate lockと&lt;a href=&quot;https://stackoverflow.com/a/68075384&quot;&gt;同じようだった&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;つまりは、S3の方が遅れていたということだろうか。&lt;/p&gt;</content:encoded></item><item><title>S3 Object Lock</title><link>https://blog.kj-dev.net/posts/l/2025/03/s3-object-lock/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/03/s3-object-lock/</guid><pubDate>Tue, 25 Mar 2025 22:15:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;s3-object-lock&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/object-lock.html&quot;&gt;S3 Object Lock&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;S3 Object Lockという機能について知った。&lt;/p&gt;
&lt;p&gt;一定期間、S3のオブジェクトを削除できないようにする機能。いくつか設定が可能だが、コンプライアンスモードというものを有効化すると、
たとえRootユーザーであっても、オブジェクトの削除ができなくなる。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://repost.aws/questions/QUe11gCMORTo-Eoi28u2rS2Q/object-lock-is-doubling-the-cost-of-archive-storage?utm_source=perplexity&quot;&gt;ストレージクラスの変更自体は可能な模様&lt;/a&gt;。削除はできないが、保持期間中により安価なストレージクラスに変更することはできそうだ。&lt;/p&gt;</content:encoded></item><item><title>LLMで作成した小さなWebツール</title><link>https://blog.kj-dev.net/posts/tools-created-by-llms/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/tools-created-by-llms/</guid><description>LLMの助けを借りて作成した小さなWebツールのコレクション</description><pubDate>Mon, 24 Mar 2025 23:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Simon Willison氏がHTMLとJavaScriptのみで作成したツールのコレクションをまとめて&lt;a href=&quot;https://tools.simonwillison.net/&quot;&gt;公開&lt;/a&gt;している。ほとんどはLLMの助けを借りたものとのこと。&lt;/p&gt;
&lt;p&gt;とても良い発想で、真似したくなった。&lt;/p&gt;
&lt;h2 id=&quot;自作ツール&quot;&gt;自作ツール&lt;/h2&gt;
&lt;p&gt;自分の助けのためにミニツールをClaudeで作成し、GitHub Pagesでホスティングしてみた。
ツールの一覧ページ:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kj-9.github.io/tools/&quot;&gt;Tools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;まだツールは2つだけ:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kj-9.github.io/tools/xml-formatter.html&quot;&gt;XML Formatter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kj-9.github.io/tools/character-byte-counter.html&quot;&gt;Character Byte Counter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;それぞれ名前の通り、XMLを整形するツールと、文字数とバイト数をカウントするツール。&lt;/p&gt;
&lt;p&gt;正直、ググったりVSCodeの拡張機能で似たようなものはある。だが広告が多かったり、自分が欲しいと思うオプションがなかったりする。サクッと自分が欲しいものをClaudeがかなりの速さとクオリティで作成してくれるので、LLMの力を借りて自作するのは簡単だし、すぐに作れる。&lt;/p&gt;
&lt;p&gt;また、GitHub Pagesでホスティングすることで、後でまた使いたくなったときにアクセスできる。&lt;/p&gt;
&lt;h2 id=&quot;character-byte-counter&quot;&gt;Character Byte Counter&lt;/h2&gt;
&lt;p&gt;Character Byte Counterは、Claude 3.7との会話で試しつつ、プロンプトを通じて機能を改善していった。&lt;/p&gt;
&lt;p&gt;初期バージョンからの変更点:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Emojiなどマルチバイト文字に対応できていなかったので機能を追加
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://claude.ai/share/889d0b98-fb3f-4ab9-86b1-8c7ae51382aa&quot;&gt;プロンプト&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;URLで文字列の分析結果をシェアできる機能を追加
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://claude.ai/share/fe68f0ff-c0f2-437f-afd3-1bbec52468df&quot;&gt;プロンプト&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(Claudeでシェアしたプロンプトも貼っていますが、URLがいつまで残るのかはわからないので)&lt;/p&gt;
&lt;p&gt;Character Byte CounterのURLシェア機能は便利で。例えば以下で”𩸽“という文字の分析結果をシェアできる:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://kj-9.github.io/tools/character-byte-counter.html?text=%F0%A9%B8%BD&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;この機能も上記promptに貼っているが、頼めばすぐに追加してくれる。Claudeは非常に優秀だ。&lt;/p&gt;</content:encoded></item><item><title>5 Things I Learned About Leadership from the Death &amp; Rebirth of Microsoft</title><link>https://blog.kj-dev.net/posts/l/2025/03/5-things-i-learned-about-leadership/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/03/5-things-i-learned-about-leadership/</guid><pubDate>Sat, 22 Mar 2025 22:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;5-things-i-learned-about-leadership-from-the-death--rebirth-of-microsoft-from-dare-obasanjo&quot;&gt;&lt;a href=&quot;https://dareobasanjo.medium.com/5-things-i-learned-about-leadership-from-the-death-rebirth-of-microsoft-3eaf42567061&quot;&gt;5 Things I Learned About Leadership from the Death &amp;#x26; Rebirth of Microsoft&lt;/a&gt; from &lt;a href=&quot;https://dareobasanjo.medium.com/&quot;&gt;Dare Obasanjo&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;マイクロソフトの2000年代後半の凋落と、そこからの復活の背後でリーダーが取ったスタンスについて。&lt;/p&gt;
&lt;p&gt;企業が(時として独善的に)設定する戦略よりも、顧客志向を優先したことが印象的。&lt;a href=&quot;http://www.25hoursaday.com/weblog/2004/10/24/TheNewStrategyTax.aspx&quot;&gt;strategy tax&lt;/a&gt;という概念も初めて知った。記事内で引用されている。&lt;/p&gt;</content:encoded></item><item><title>OpenRouterで無料でLLMのAPIを利用する</title><link>https://blog.kj-dev.net/posts/openrouter-llm-cli/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/openrouter-llm-cli/</guid><description>OpenRouterの使い方</description><pubDate>Wed, 19 Mar 2025 23:00:00 GMT</pubDate><content:encoded>&lt;h4 id=&quot;table-of-contents&quot;&gt;Table of contents&lt;/h4&gt;
&lt;p&gt;&lt;/p&gt;&lt;details&gt;&lt;summary&gt;Open Table of contents&lt;/summary&gt;&lt;p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#openrouter&quot;&gt;OpenRouter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%81%8C%E5%BE%97%E6%84%8F%E3%81%AA%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AF&quot;&gt;日本語が得意なモデルは?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#openrouter%E3%81%AEapi%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B&quot;&gt;OpenRouterのAPIを利用する&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AE%E5%87%BA%E5%8A%9B%E3%82%92%E3%83%91%E3%82%A4%E3%83%97%E3%81%97%E3%81%A6%E6%B8%A1%E3%81%99&quot;&gt;コマンドの出力をパイプして渡す&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E3%81%BE%E3%81%A8%E3%82%81&quot;&gt;まとめ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E8%BF%BD%E8%A8%9820250318-openrouter%E3%81%8B%E3%82%89%E7%84%A1%E6%96%99%E3%81%A7gemini%E3%81%8C%E4%BD%BF%E3%81%88%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F&quot;&gt;追記(2025/03/18): OpenRouterから無料でGeminiが使えるようになった&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;/p&gt;&lt;/details&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;openrouter&quot;&gt;OpenRouter&lt;/h2&gt;
&lt;p&gt;無料で使えるLLMのAPIを調べていたところ、&lt;a href=&quot;https://openrouter.ai/&quot;&gt;OpenRouter&lt;/a&gt;というサービスを見つけた。&lt;/p&gt;
&lt;p&gt;OpenRouterでは多くのLLMモデルを利用できるのだが、執筆時点で無料で利用できるのは「100%OFF」と表示されている以下の8モデル:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/openrouter-free-models.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;OpenRouterの無料モデル&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;利用できるモデルの詳細は&lt;a href=&quot;https://openrouter.ai/docs#models&quot;&gt;Supported Models&lt;/a&gt;を参照。&lt;/p&gt;
&lt;h2 id=&quot;日本語が得意なモデルは&quot;&gt;日本語が得意なモデルは?&lt;/h2&gt;
&lt;p&gt;WebUI上から複数モデルとChatすることができるので、無料モデルがどれくらい日本語を理解できるのか見てみた。&lt;/p&gt;
&lt;p&gt;ざっとみただけだが、OpenChat3.5はなかなか良さそう。
その他のモデルは少々厳しいか？&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/openrouter-japanese-chat.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;無料モデルとの日本語会話&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;openrouterのapiを利用する&quot;&gt;OpenRouterのAPIを利用する&lt;/h2&gt;
&lt;p&gt;APIを利用するには、OpenRouterのアカウントを作成し、APIキーを取得するだけ。クレジットカードの登録も不要。&lt;/p&gt;
&lt;p&gt;OpenAIのAPIと互換性があるので、Pythonであれば&lt;code&gt;pip install openai&lt;/code&gt;で利用開始できる。&lt;a href=&quot;https://openrouter.ai/docs#quick-start&quot;&gt;Quick Start&lt;/a&gt;にサンプルコードものっている。&lt;/p&gt;
&lt;p&gt;今回は個人的に気に入っている、&lt;a href=&quot;https://llm.datasette.io/en/stable/&quot;&gt;LLM&lt;/a&gt;というCLIツールを使ってAPIを利用してみる。&lt;code&gt;LLM&lt;/code&gt;は名前の通り、LLMをターミナルから利用できるCLIツール。(分かりやすいがややこしい。)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;LLM&lt;/code&gt;では色々なPluginが存在しているのだが、OpenRouterのAPIを利用するための&lt;a href=&quot;https://github.com/simonw/llm-openrouter&quot;&gt;Plugin&lt;/a&gt;もあり、サクッと試すにはおすすめ。&lt;/p&gt;
&lt;p&gt;cliの利用準備:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;pip&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; llm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;llm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; llm-openrouter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;llm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; keys&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; openrouter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# プロンプトで発行したAPIキーを入力&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで準備は完了。以下のように利用できる:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;llm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; openrouter/openchat/openchat-7b&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;PythonでCSVファイルを読み込むコードを書いて&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-m&lt;/code&gt;は利用するモデルの指定で、&lt;code&gt;openrouter/openchat/openchat-7b&lt;/code&gt;は先ほどのOpenChat3.5。&lt;/p&gt;
&lt;p&gt;以下LLMからの回答:&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;&lt;p&gt;PythonでCSVファイルを読み込むには、&lt;code&gt;csv&lt;/code&gt;モジュールを使用します。以下に例を示します。&lt;/p&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; csv&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# CSVファイルのパス&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;csv_file_path &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;example.csv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# CSVファイルを読み込む&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;csv_file_path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D7DBE0&quot;&gt; mode&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D7DBE0&quot;&gt; encoding&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;utf-8&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; csvfile&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;    # CSVファイルを読み込む&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    csv_reader &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; csv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;reader&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;csvfile&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;    # ファイル内の行を順に読み込む&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; row &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; csv_reader&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;row&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt;この例では、&lt;code&gt;example.csv&lt;/code&gt;という名前のCSVファイルを読み込み、その内容を順に表示しています。&lt;code&gt;csv.reader&lt;/code&gt;を使用して、CSVファイルの行を順に読み込むことができます。&lt;code&gt;csvfile&lt;/code&gt;は、&lt;code&gt;with&lt;/code&gt;文の中で自動的に閉じられるため、ファイルが適切にクローズされることが保証されます。&lt;/p&gt;&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;無料にしてはなかなか良さそうだ。&lt;/p&gt;
&lt;h2 id=&quot;コマンドの出力をパイプして渡す&quot;&gt;コマンドの出力をパイプして渡す&lt;/h2&gt;
&lt;p&gt;だが、これだけだとGPT3.5使えば良い話なので、コマンド結果をパイプしながら作成し、&lt;code&gt;LLM&lt;/code&gt;に渡してみる。&lt;/p&gt;
&lt;p&gt;無料で使える&lt;a href=&quot;https://open-meteo.com/&quot;&gt;天気予報API&lt;/a&gt;をcurlで叩き、東京駅周辺の天気情報をJSON形式で受け取り、LLMに渡して要約してもらった:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# 東京駅の緯度軽度&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;LON&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;139.76&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;LAT&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;35.68&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# JSON形式で天気予報を取得し、jqで整形してからLLMに渡す&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;https://api.open-meteo.com/v1/forecast?latitude=${&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C5E478&quot;&gt;LAT&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;}&amp;#x26;longitude=${&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C5E478&quot;&gt;LON&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;}1&amp;#x26;current=temperature_2m,wind_speed_10m&amp;#x26;hourly=temperature_2m,relative_humidity_2m,wind_speed_10m&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; jq&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; llm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; openrouter/openchat/openchat-7b&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt;  -s&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;あなたは優秀な日本語アシスタントです。天気予報のAPIからのレスポンスをJSON形式で渡すので、内容を要約してください&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt;  -o&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; max_tokens&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt; 1000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここで、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt;はシステムプロンプトの指定。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o&lt;/code&gt;はモデルのオプションの指定。&lt;code&gt;max_tokens&lt;/code&gt;は生成するトークンの最大数を指定。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;LLM&lt;/code&gt;で利用できるオプションは&lt;code&gt;llm models --options&lt;/code&gt;で表示できる。(&lt;a href=&quot;https://llm.datasette.io/en/stable/python-api.html#model-options&quot;&gt;参考&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;以下LLMからの回答:&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;&lt;p&gt;天気予報APIから受けたデータを要約しました。現在の気温は10.9℃で、最高気温は21.8℃であり、最低気温は1.8℃です。湿度は95%で、風速は11.8km/hです。この週の天気予報は、多くの時間で雨が降り、気温は低い予定です。1月20日～26日の間、最高気温は11℃、最低気温は1℃です。湿度は高く、風速は中程度です。&lt;/p&gt;&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;日本語として違和感のない文章で要約してくれている。&lt;/p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;/h2&gt;
&lt;p&gt;OpenAIのAPIは有料だが、OpenRouterのAPIは無料で利用できる。ChatGPT程の精度はないが、無料の範囲でそれなりに日本語も扱えるモデルも揃っているので、十分に遊べる。&lt;/p&gt;
&lt;p&gt;今回はCLIから利用したが、openaiのAPIを使ってPythonなりJavascriptで実装してみるのも良さそうだ。&lt;/p&gt;
&lt;h2 id=&quot;追記20250318-openrouterから無料でgeminiが使えるようになった&quot;&gt;追記(2025/03/18): OpenRouterから無料でGeminiが使えるようになった&lt;/h2&gt;
&lt;p&gt;久々に見ていたら、GeminiやGemmaなど、googleのモデルもOpenRouterで無料で利用できるようになっていた。(GeminiのAPI自体は、OpenRouterを使わずとも、Googleアカウントがあればクレカ登録不要で利用はできる)&lt;/p&gt;
&lt;p&gt;llm-openrouterのPluginも進化していて、&lt;a href=&quot;https://simonwillison.net/2025/Mar/10/llm-openrouter-04/&quot;&gt;v0.4&lt;/a&gt;では無料のモデルを一覧で表示できるようになった。&lt;/p&gt;
&lt;p&gt;Googleの無料モデルは、執筆時点で以下:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;❯&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; llm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; openrouter&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; models&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --free&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; google&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; id:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; google/gemma-3-1b-it:free&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; id:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; google/gemma-3-4b-it:free&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; id:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; google/gemma-3-12b-it:free&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; id:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; google/gemma-3-27b-it:free&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; id:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; google/gemini-2.0-flash-lite-preview-02-05:free&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; id:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; google/gemini-2.0-pro-exp-02-05:free&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; id:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; google/gemini-2.0-flash-thinking-exp:free&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; id:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; google/gemini-2.0-flash-thinking-exp-1219:free&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; id:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; google/gemini-2.0-flash-exp:free&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; id:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; google/gemini-exp-1206:free&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; id:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; google/learnlm-1.5-pro-experimental:free&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; id:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; google/gemma-2-9b-it:free&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;レートリミットの制限はあるが、もはや&lt;code&gt;OpenChat3.5&lt;/code&gt;とは比べ物にならない精度が期待できる。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;❯&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; llm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;openrouter/google/gemini-2.0-flash-lite-preview-02-05:free&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; こ&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; んにちは。あなたは日本語が得意ですか？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;INFO:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; HTTP&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; Request:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; POST&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; https://openrouter.ai/api/v1/chat/completions&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;はい、日本語は得意です。日本語の読み書き、会話、理解はできます。&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; 質問や何かお手伝いできることがあれば、遠慮なくお尋ねください。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;1年前はOpenChat3.5が精度が高いと感じていたが、今はGoogleのGeminiが無料で使えるので、もはやOpenChat3.5は使う理由がないかもしれない。1年でここまで進むとは、驚きだ。&lt;/p&gt;
&lt;p&gt;ちなみに&lt;a href=&quot;https://github.com/simonw/llm-gemini&quot;&gt;llm-gemini&lt;/a&gt;というGeminiAPI専用のPluginもあるので、Geminiを使う場合はこちらを使うと良い。JSON形式での出力や、音声、動画ファイルの入力などにも対応していて、とても使いやすい。&lt;/p&gt;
&lt;p&gt;さらに、&lt;code&gt;llm openrouter key&lt;/code&gt;でAPIキーの使用状況も確認できる:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;❯&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; llm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; openrouter&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;INFO:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; HTTP&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; Request:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; GET&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; https://openrouter.ai/api/v1/auth/key&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;  &quot;label&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;sk-or-v1-a3b...0a8&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;  &quot;limit&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; null,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;  &quot;usage&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; 6.1435e-05,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;  &quot;is_provisioning_key&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;  &quot;limit_remaining&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; null,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;  &quot;is_free_tier&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;  &quot;rate_limit&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;    &quot;requests&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; 10,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;    &quot;interval&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;10s&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;rate limitの状態や、free_tierの状態も表示される。&lt;/p&gt;</content:encoded></item><item><title>Findyイベントアーカイブ</title><link>https://blog.kj-dev.net/posts/l/2025/03/findy-archive/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/03/findy-archive/</guid><pubDate>Mon, 10 Mar 2025 23:30:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;findyイベントアーカイブ&quot;&gt;&lt;a href=&quot;https://findy-code.io/events/archives&quot;&gt;Findyイベントアーカイブ&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;エンジニアの転職サービスでお馴染みの&lt;a href=&quot;https://findy-code.io/&quot;&gt;Findy&lt;/a&gt;は、エンジニア向けのイベントも開催している。
色々な技術トピックについての&lt;a href=&quot;https://findy-code.io/events/archives&quot;&gt;過去のアーカイブ動画&lt;/a&gt;が公開されていて、なかなか良さそうだ。
動画の閲覧にはアカウント作成は必要になる。&lt;/p&gt;
&lt;p&gt;直近で気になったもの:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://findy-code.io/events/wDAX51FtYST43&quot;&gt;Apache Icebergと超えていくデータレイクの限界 -S3とSnowflake活用事例-&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://findy-code.io/events/vrGiTMOfmJ9LJ&quot;&gt;DuckDBの魅力解剖！〜現場から見る活用術とその可能性〜&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://findy-code.io/events/HPoLmUm8aq0VV&quot;&gt;LayerX・イオン・JALインフォテックに学ぶ Terraformによる自動化・効率化の最前線&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ジャンルは幅広く、データエンジニアリング、Web開発、インフラ、セキュリティ、マネジメントなど、様々なトピックがある。&lt;/p&gt;</content:encoded></item><item><title>llmをMacBook Air M2上で無料で動かす (mlxとggufを比較)</title><link>https://blog.kj-dev.net/posts/llm-on-mac-book-air-m2/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/llm-on-mac-book-air-m2/</guid><description>ローカルでの実行方法と比較結果</description><pubDate>Thu, 20 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://simonwillison.net/2025/Feb/15/llm-mlx/#atom-everything&quot;&gt;Run LLMs on macOS using llm-mlx and Apple’s MLX framework&lt;/a&gt;という記事で、&lt;a href=&quot;https://github.com/ml-explore/mlx&quot;&gt;mlx&lt;/a&gt;を使って、macOS上でllmを動かす方法が紹介されている。&lt;/p&gt;
&lt;p&gt;mlxとはAppleが開発するApple Siliconのための機械学習フレームワーク。&lt;a href=&quot;https://pypi.org/project/mlx-lm/&quot;&gt;mlx-lm&lt;/a&gt;というllmをmlxで動作させるためのPythonライブラリも提供されている。&lt;/p&gt;
&lt;p&gt;しばらく自身のMacBook Air上でllmを動かしていなかったので、自分のMacBookでmlxを利用したllmの実行を試してみることにした。&lt;/p&gt;
&lt;h2 id=&quot;pcのスペック&quot;&gt;PCのスペック&lt;/h2&gt;
&lt;p&gt;MacBook Air M2 (2022)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;16GB memory&lt;/li&gt;
&lt;li&gt;512GB SSD&lt;/li&gt;
&lt;li&gt;Sequoia 15.3&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;lm-studioを使ってローカルでllmを実行&quot;&gt;LM Studioを使ってローカルでllmを実行&lt;/h2&gt;
&lt;p&gt;今回は&lt;a href=&quot;https://lmstudio.ai/&quot;&gt;LM Studio&lt;/a&gt;というオープンソースのデスクトップアプリを使ってllmを動かしてみる。&lt;/p&gt;
&lt;p&gt;LM Studioは従来のllmのファイル形式であるggufだけでなく、mlxのファイル形式もサポートしている。(&lt;a href=&quot;https://lmstudio.ai/blog/lmstudio-v0.3.4&quot;&gt;v0.3.4&lt;/a&gt;以降でmlxがサポートされた)&lt;/p&gt;
&lt;p&gt;LM StudioのUIから、HuggingFaceが提供するmlx/ggufのモデルを検索し、ダウンロードして使うことができる。&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/lm-studio-download-models.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;lm-studio-download-models&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;mistral-7bをmlxggufで比較&quot;&gt;Mistral 7Bをmlx/ggufで比較&lt;/h2&gt;
&lt;p&gt;16GBメモリのMacBook Airのため、巨大なモデルは動かすことはできない。今回は&lt;code&gt;Mistral 7B Instruct v0.3&lt;/code&gt;の4GB程度のモデルファイルでmlx/ggufそれぞれの形式を比較してみる。&lt;/p&gt;
&lt;p&gt;入力プロンプトは 「ツリーを巡回するPythonコードを簡潔に説明して」&lt;/p&gt;
&lt;h3 id=&quot;tldr&quot;&gt;TL;DR&lt;/h3&gt;
&lt;p&gt;先に結論だが、mlxとggufとで大差はなさそうだった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modelサイズやメモリ使用量はmlxの方が少し小さい (-0.3GBほど)&lt;/li&gt;
&lt;li&gt;Token Speedはmlxの方がわずかに速い(+3tok/sec)&lt;/li&gt;
&lt;li&gt;回答内容はどちらも良さそう
&lt;ul&gt;
&lt;li&gt;どちらもちゃんとコードを生成できている&lt;/li&gt;
&lt;li&gt;ggufの方が回答内容が少し長いが、mlxの方が回答内容が簡潔である&lt;/li&gt;
&lt;li&gt;日本語も漢字が中国語っぽい部分はあるが、どちらも十分理解できる内容である&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;あくまで今回の比較は、4GB程度のモデルでの比較であるため、より巨大なモデルでの比較を行うと、性能差がより顕著に出ると思われる。&lt;/p&gt;
&lt;p&gt;次の表により詳細な結果をまとめた:&lt;/p&gt;








































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;mlx&lt;/th&gt;&lt;th&gt;gguf&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Model Name&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://huggingface.co/mlx-community/Mistral-7B-Instruct-v0.3-4bit&quot;&gt;Mistral 7B Instruct v0.3 4bit&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://huggingface.co/lmstudio-community/Mistral-7B-Instruct-v0.3-GGUF&quot;&gt;Mistral 7B Instruct v0.3 Q4_K_M&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;File Size&lt;/td&gt;&lt;td&gt;4.08 GB&lt;/td&gt;&lt;td&gt;4.37 GB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Memory Usage&lt;/td&gt;&lt;td&gt;4.28 GB&lt;/td&gt;&lt;td&gt;4.71 GB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Token Speed&lt;/td&gt;&lt;td&gt;20.81 tok/sec&lt;/td&gt;&lt;td&gt;17.60 tok/sec&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Time to First Token&lt;/td&gt;&lt;td&gt;0.63s&lt;/td&gt;&lt;td&gt;0.52s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Output Tokens&lt;/td&gt;&lt;td&gt;531&lt;/td&gt;&lt;td&gt;639&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;実際の回答:&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;mlxの回答&lt;/summary&gt;
&lt;blockquote&gt;&lt;p&gt;Pythonでツリー（Tree）を輪遡させる（Recursively traverse）シンプルなコードは次のようになります：&lt;/p&gt;&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; traverse&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;   if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;       # 現在のノードを処理&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;       func&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;       # 子ノード（左側と右側）について、同じ処理を繰り返してください&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;       traverse&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;node.left&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;       traverse&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;node.right&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# 木構造で表現されたデータを持ち、leftとrightに子ノードがあるnodeオブジェクト&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; MyNode&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # 例: Root Node&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;left &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; MyNode&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;right &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; MyNode&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;left&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;left &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; MyNode&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;left&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;right &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; MyNode&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# 木を輪遡させる処理&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;traverse&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt; print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # 上記の構造に対して、各ノードを出力&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;上記のコードでは、&lt;code&gt;traverse()&lt;/code&gt; 関数に木構造を持ち、&lt;code&gt;func&lt;/code&gt; を呼び出すようになっています。この &lt;code&gt;func&lt;/code&gt; 関数は処理を行うたびに、渡されるノードオブジェクトに対して何らかの処理を行います。一度呼び出されるたびに、現在のノードを処理してから子ノード（左側と右側）について、再帰的にこの処理を繰り返します。&lt;/p&gt;&lt;p&gt;上記の例では、&lt;code&gt;print()&lt;/code&gt; 関数を &lt;code&gt;func&lt;/code&gt; として与えています。これにより、rootノードから、子ノードを辿ってrootノードから根拠した木構造の全てのノードが出力されます。&lt;/p&gt;&lt;/blockquote&gt;
&lt;/details&gt;
&lt;details&gt;&lt;summary&gt;ggufの回答&lt;/summary&gt;
&lt;blockquote&gt;&lt;p&gt;以下は、Pythonで木（Tree）を深さ優先探索（Depth-First Search, DFS）または幅優先探索（Breadth-First Search, BFS）する方法の簡単な例です。&lt;/p&gt;&lt;p&gt;これらの例は、Python標準ライブラリに含まれる&lt;code&gt;collections.deque&lt;/code&gt;を使用して、ノードを追跡したり、前へ戻れたりすることが可能です。&lt;/p&gt;&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# 深さ優先探索 (Depth-First Search, DFS)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#FFCB8B&quot;&gt; Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;   def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt; __init__&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt; val&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#8EACE3&quot;&gt;       self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;val &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; val&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#8EACE3&quot;&gt;       self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; dfs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;   print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;node.val&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;   for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; child &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;       dfs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;child&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;A&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;B&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;D&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;F&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;C&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;G&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;dfs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;  # root, A, D, C, B, E, F, G の順に出力されます。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# 幅優先探索 (Breadth-First Search, BFS)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; collections &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; deque&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; bfs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;   q &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; deque&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;   q&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;   while&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; q&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;       current_node &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; q&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;popleft&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;       print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;current_node.val&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;       for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; child &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; current_node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;           q&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;child&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root_bfs &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# ノードの設定は同じですが、DFSと異なり次第に子ノードを追加します。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root_bfs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;A&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root_bfs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;B&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root_bfs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;D&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root_bfs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root_bfs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;F&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root_bfs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;C&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;root_bfs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;G&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;bfs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;root_bfs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;  # root, A, B, C, D, E, F, G の順に出力されます。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;/details&gt;
&lt;h2 id=&quot;おまけ-cliで実行する&quot;&gt;おまけ: CLIで実行する&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://simonwillison.net/2025/Feb/15/llm-mlx/#atom-everything&quot;&gt;冒頭の記事&lt;/a&gt;で紹介されているが、CLIツール&lt;a href=&quot;https://llm.datasette.io/en/stable/index.html#&quot;&gt;&lt;code&gt;LLM&lt;/code&gt;&lt;/a&gt;でもmlxを使ってllmを動かすことができる。&lt;/p&gt;
&lt;p&gt;まず&lt;a href=&quot;https://docs.astral.sh/uv/&quot;&gt;uv&lt;/a&gt;を使って&lt;code&gt;LLM&lt;/code&gt;をインストールする:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;uv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; llm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --python&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt; 3.12&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここで&lt;code&gt;--python 3.12&lt;/code&gt;は、内部で利用されている&lt;a href=&quot;https://github.com/simonw/llm-mlx/issues/7#issuecomment-2661192529&quot;&gt;&lt;code&gt;sentencepiece&lt;/code&gt;のwheelがpython3.12までしか提供されていない&lt;/a&gt;ため指定している。&lt;/p&gt;
&lt;p&gt;プラグインである&lt;a href=&quot;https://github.com/simonw/llm-mlx&quot;&gt;&lt;code&gt;llm-mlx&lt;/code&gt;&lt;/a&gt;をインストールする:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;llm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; llm-mlx&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;mlxモデルファイルは、CLIからダウンロードすることもできるが、せっかくなのでLM Studioでダウンロードしたファイルを使いまわしたい。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;~/.lmstudio/models/mlx-community&lt;/code&gt;にダウンロードしたmlxモデルが保存されている:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;❯&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; ls&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -l&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; ~/.lmstudio/models/mlx-community&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;total&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;drwxr-xr-x@&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt; 9&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; kh03&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;  staff&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;  288&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; Feb&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt; 18&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; 21:31&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; Mistral-7B-Instruct-v0.3-4bit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このモデルファイルを&lt;code&gt;LLM&lt;/code&gt;で使うためには、モデル定義を記述するjsonファイルを編集する必要がある。
以下でjsonを開ける:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;❯&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;llm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; mlx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; models-file&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;jsonに以下のキーを追加する:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  &quot;~/.lmstudio/models/mlx-community/Mistral-7B-Instruct-v0.3-4bit&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;    &quot;aliases&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;lmstudio&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;キー自体は、LM Studioでダウンロードしたモデルのパスを指定し、&lt;code&gt;aliases&lt;/code&gt;にはCLIで利用するモデルの名前を自由に指定する。
(ここのモデル登録は少々面倒なので、コマンドを追加できないか&lt;a href=&quot;https://github.com/simonw/llm-mlx/issues/12&quot;&gt;Issue&lt;/a&gt;作成した)&lt;/p&gt;
&lt;p&gt;あとはaliasを指定して、&lt;code&gt;LLM&lt;/code&gt;を実行する:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;❯&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; llm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; lmstudio-mistral&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; hi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;/h2&gt;
&lt;p&gt;より大きなモデルをローカルで利用したい場合はMacBook Proの上位モデルが適しているかもしれないが、今回のような小規模なモデルであれば、MacBook Air M2でも十分動かすことができた。&lt;/p&gt;
&lt;p&gt;何よりもローカルで動かせば無料だし、外部のサーバーに依存しないので、セキュリティ的にも安心である。色々と試すにはかなりお勧めできる。&lt;/p&gt;
&lt;p&gt;またCLIを利用すれば、ほかのプログラムとPipeを通じて組み合わせることもできる。&lt;/p&gt;</content:encoded></item><item><title>プラグインで拡張可能なソフトウェアを設計・実装する方法 by Simon Willison</title><link>https://blog.kj-dev.net/posts/l/2025/02/how-to-design-and-implement-extensible-software-with-plugins/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/02/how-to-design-and-implement-extensible-software-with-plugins/</guid><pubDate>Fri, 14 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;プラグインで拡張可能なソフトウェアを設計実装する方法-by-simon-willison&quot;&gt;&lt;a href=&quot;https://youtu.be/IdTHaCo8gKY?feature=shared&quot;&gt;プラグインで拡張可能なソフトウェアを設計・実装する方法&lt;/a&gt; by Simon Willison&lt;/h2&gt;
&lt;p&gt;via &lt;a href=&quot;https://2024.djangocon.us/talks/how-to-design-and-implement-extensible-software-with-plugins&quot;&gt;DjangoCon 2024&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;DjangoCon 2024でのSimon Willison氏による、pluginアーキテクチャについての貴重なトークがYoutubeで公開されている。&lt;/p&gt;
&lt;p&gt;氏が作成したPluginアーキテクチャを採用した実例が紹介されている:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://llm.datasette.io/en/stable/&quot;&gt;llm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://datasette.io/&quot;&gt;datasette&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://djp.readthedocs.io/en/latest/index.html#&quot;&gt;djp (django plugin systems)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;すべてPytestのPluginアーキテクチャを支える、&lt;code&gt;pluggy&lt;/code&gt;というライブラリを活用している。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pluggy&lt;/code&gt;もプラグインシステムも話題にのぼることは少ない(と感じるが)、実例も含み示唆に富む氏のトークは、pluginアーキテクチャを採用するメリットや、その実装方法についての理解を深めるのに役立つ。&lt;/p&gt;</content:encoded></item><item><title>エンジニアの仕事を昇進につなげるには</title><link>https://blog.kj-dev.net/posts/l/2025/02/how-to-turn-engineering-work-into-a-promotion/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/02/how-to-turn-engineering-work-into-a-promotion/</guid><pubDate>Tue, 11 Feb 2025 16:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;how-to-turn-engineering-work-into-a-promotion-エンジニアの仕事を昇進につなげるには-by-anna-jean-mcdougall-via-gitnation&quot;&gt;&lt;a href=&quot;https://gitnation.com/contents/how-to-turn-engineering-work-into-a-promotion&quot;&gt;How to Turn Engineering Work into a Promotion ~エンジニアの仕事を昇進につなげるには~&lt;/a&gt; by &lt;a href=&quot;https://www.annamcdougall.com/&quot;&gt;Anna Jean McDougall&lt;/a&gt; via &lt;a href=&quot;https://gitnation.com/&quot;&gt;GitNation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;具体的で行動に移しやすいトーク内容、&lt;a href=&quot;https://gitnation.com/&quot;&gt;GitNation&lt;/a&gt;で無料で視聴できる。&lt;/p&gt;
&lt;p&gt;GitNationでは色々なカンファレンスの動画が視聴でき、中には有料のものもあるが、無料で見れるものも多い。&lt;/p&gt;</content:encoded></item><item><title>C4ダイアグラム</title><link>https://blog.kj-dev.net/posts/l/2025/02/c4-diagram/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/02/c4-diagram/</guid><pubDate>Tue, 11 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;c4ダイアグラム-via-hacker-news-comment-on-7-common-mistakes-in-architecture-diagrams&quot;&gt;&lt;a href=&quot;https://c4model.com/&quot;&gt;C4ダイアグラム&lt;/a&gt; via &lt;a href=&quot;https://news.ycombinator.com/item?id=43000480&quot;&gt;Hacker News Comment&lt;/a&gt; on &lt;a href=&quot;https://www.ilograph.com/blog/posts/diagram-mistakes/&quot;&gt;7 Common Mistakes in Architecture Diagrams&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;C4ダイアグラムは、ソフトウェアのアーキテクチャを4つのレベルで整理する方法論。&lt;a href=&quot;https://c4model.com/introduction&quot;&gt;イントロダクション&lt;/a&gt;がわかりやすい。&lt;/p&gt;</content:encoded></item><item><title>リンクブログを作る</title><link>https://blog.kj-dev.net/posts/l/2025/02/build-a-link-blog/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/l/2025/02/build-a-link-blog/</guid><pubDate>Fri, 07 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;リンクブログを作る-via-hacker-news&quot;&gt;&lt;a href=&quot;https://xuanwo.io/links/2025/01/link-blog/&quot;&gt;リンクブログを作る&lt;/a&gt; via &lt;a href=&quot;https://news.ycombinator.com/item?id=42933383&quot;&gt;Hacker News&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;XuanwoはSimon Willisonに触発され、リンクブログを作ることにした。そして自分も触発されたので、リンクブログを作ることにした。&lt;/p&gt;
&lt;p&gt;リンクブログとは&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;「みつけたこと」をかく小さなブログ&lt;/li&gt;
&lt;li&gt;リンクにすこし付け加える
&lt;ul&gt;
&lt;li&gt;簡単なサマリ、コメント&lt;/li&gt;
&lt;li&gt;リンク先の引用もするかもすれない&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;コードの切れ端など、そのほかのリンクを含むかもしれない&lt;/li&gt;
&lt;li&gt;常に、ソースを提供した人のなまえをいれる&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>pytestでフラグ指定した時のみ統合テストを実行する</title><link>https://blog.kj-dev.net/posts/pytest-optin-integration-test/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/pytest-optin-integration-test/</guid><description>pytestと&quot;たまに実行する&quot;統合テスト</description><pubDate>Wed, 04 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;pytestを使って、統合テストを行いたい。
統合テストでは、外部のAPIやリソースにアクセスする。
そのため、pytest実行時にフラグを指定した場合のみ、統合テストを実行するようにしたい。&lt;/p&gt;
&lt;p&gt;実装としては、&lt;code&gt;@pytest.mark&lt;/code&gt;をつかって、テストをマークしておく&lt;a href=&quot;https://til.simonwillison.net/pytest/only-run-integration&quot;&gt;方法&lt;/a&gt;がある。&lt;/p&gt;
&lt;p&gt;この方法ではテストファイルのディレクトリ構成に関係なく、個々のテストを統合テストとしてマークする。
これはこれで便利だが、今回は、「特定のディレクトリ内のテストファイル」をすべて統合テストとして実行する方法を試してみた。&lt;/p&gt;
&lt;h2 id=&quot;pytestの設定&quot;&gt;pytestの設定&lt;/h2&gt;
&lt;p&gt;テストコードのディレクトリ構成は以下のようになっているとする:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;tests/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── conftest.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── integration/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── conftest.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── test_integration.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── test_unit.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここで、&lt;code&gt;integration/&lt;/code&gt;ディレクトリ内のテストファイルを統合テストとして、&lt;code&gt;--integration&lt;/code&gt;フラグを指定した場合のみ実行したい:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;pytest&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --integration&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ベースとなる&lt;code&gt;tests/conftest.py&lt;/code&gt;に以下のコードを追加する:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; pytest_addoption&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt;parser&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    parser&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;addoption&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;--integration&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D7DBE0&quot;&gt;        action&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;store_true&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D7DBE0&quot;&gt;        default&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#FF5874&quot;&gt;False&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D7DBE0&quot;&gt;        help&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;run integration tests&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで、&lt;code&gt;--integration&lt;/code&gt;フラグを&lt;code&gt;pytest&lt;/code&gt;コマンドに指定できるようになる。&lt;/p&gt;
&lt;p&gt;次に、&lt;code&gt;tests/integration/conftest.py&lt;/code&gt;に以下のコードを追加する:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; pytest_collection_modifyitems&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt; items&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;    # skip all integration tests if not explicitly requested&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;option&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;integration&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;        skip_integration &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; pytest&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;mark&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;skip&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D7DBE0&quot;&gt;reason&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;need --integration option to run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; item &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; items&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;integration&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; item&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;keywords&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;                item&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;add_marker&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;skip_integration&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで、&lt;code&gt;--integration&lt;/code&gt;フラグが指定されていない場合、&lt;code&gt;integration/&lt;/code&gt;内のテストはスキップされるようになる。&lt;/p&gt;
&lt;h2 id=&quot;例&quot;&gt;例&lt;/h2&gt;
&lt;p&gt;とある&lt;a href=&quot;https://github.com/kj-9/bqm&quot;&gt;&lt;code&gt;bqm&lt;/code&gt;&lt;/a&gt;というレポジトリにおける&lt;code&gt;--integration&lt;/code&gt;フラグを指定した場合のみ実行されるテストコードの追加&lt;a href=&quot;https://github.com/kj-9/bqm/commit/49f983cad0d1df32740ea2009a611f435499258c#diff-c87c5173e88bb0f60b00107f4586304f4869a976a4f998425efe3481c0db9f56R4&quot;&gt;コミット&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;統合テストとして、GCPのBigQueryにアクセスするテストコードを書いている。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--integration&lt;/code&gt;フラグを指定せずにテストを実行すると、統合テストはスキップされる:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;log&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;❯ pytest tests/integration -vv&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;==== test session starts ============================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;platform darwin -- Python &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;12&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;pytest-8.3.3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;pluggy-1.5.0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; -- /Users/hoge/work/repos/bqm/.venv/bin/python3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;cachedir: .pytest_cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;rootdir: /Users/hoge/work/repos/bqm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;configfile: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;pyproject.toml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;plugins: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;syrupy-4.7.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;collected &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; items&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;tests/integration/test_integration.py::test_integration SKIPPED (need --integration option to run) [ &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;%]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;tests/integration/test_integration.py::test_tables_dryrun SKIPPED (need --integration option to run) [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;%]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;=== &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; skipped in &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;.32s ==============================================&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;--integration&lt;/code&gt;フラグを指定してテストを実行すると、統合テストが実行される (このツールでは、&lt;code&gt;--project&lt;/code&gt;でGCPのプロジェクトIDも指定する必要がある):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;log&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;❯ python -m pytest  --integration --project hoge-gcp -vv&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;==== test session starts ============================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;platform darwin -- Python &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;12&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;pytest-8.3.3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;pluggy-1.5.0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; -- /Users/hoge/work/repos/bqm/.venv/bin/python&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;cachedir: .pytest_cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;rootdir: /Users/hoge/work/repos/bqm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;configfile: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;pyproject.toml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;plugins: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;syrupy-4.7.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;collected &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; items&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;tests/integration/test_integration.py::test_integration PASSED [ &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;%]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;tests/integration/test_integration.py::test_tables_dryrun PASSED [ &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;40&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;%]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;tests/test_bqm.py::test_version PASSED [ &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;60&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;%]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;tests/test_bqm.py::test_tables_dryrun PASSED [ &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;80&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;%]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;tests/test_bqm.py::test_views_dryrun PASSED [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;%]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;---snapshot report summary ------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; snapshots passed.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;=== &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; passed in &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;.97s ===============================================&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded></item><item><title>pythonスクリプトをCLIツールとしてインストールする</title><link>https://blog.kj-dev.net/posts/python-script-to-cli/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/python-script-to-cli/</guid><description>uvでインストール可能なミニマムな構成</description><pubDate>Mon, 28 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;時たま利用する、単体のPythonスクリプトがいくつかある。&lt;/p&gt;
&lt;p&gt;利用する頻度としては微妙なラインで、わざわざパッケージ化するほどではないが、誰かに共有したり、複数の端末でインストールしたい場合には、1発のコマンドでインストールできると便利だ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.astral.sh/uv/&quot;&gt;&lt;code&gt;uv&lt;/code&gt;&lt;/a&gt;の&lt;a href=&quot;https://docs.astral.sh/uv/reference/cli/#uv-tool-install&quot;&gt;&lt;code&gt;uv tool install&lt;/code&gt;&lt;/a&gt;コマンドを使うと、簡単に隔離された環境にPythonパッケージをCLIとしてインストールできる。だが、現状は単一のPythonスクリプトをインストールすることはできない。少なくとも、1つのPythonスクリプトに加えて、&lt;code&gt;pyproject.toml&lt;/code&gt;が必要になる。&lt;/p&gt;
&lt;p&gt;単一のPythonスクリプトをインストール可能にする&lt;a href=&quot;https://github.com/astral-sh/uv/issues/7242&quot;&gt;feature request&lt;/a&gt;が&lt;code&gt;uv&lt;/code&gt;のレポジトリで作成されているが、まだ実装されていないのが現状だ。&lt;/p&gt;
&lt;h2 id=&quot;copier-template&quot;&gt;copier template&lt;/h2&gt;
&lt;p&gt;そこで&lt;a href=&quot;https://copier.readthedocs.io/en/stable/&quot;&gt;copier&lt;/a&gt;を使って、PythonスクリプトをCLIツールとして&lt;code&gt;uv tool install&lt;/code&gt;でインストールするためのミニマムなファイルを生成するテンプレートを作成した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kj-9/uv-tool-min-copier&quot;&gt;uv-tool-min-copier&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ファイルを生成するには、uvをインストールした環境で、以下のコマンドを実行する:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;uvx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; copier&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; copy&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; gh:kj-9/uv-tool-min-copier&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; your-tool-dir&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;プロンプトでいくつかの質問に回答を求められるので、生成するCLIツール名など適宜入力する。&lt;/p&gt;
&lt;p&gt;途中で&lt;code&gt;&quot;Do you want to use Click for command line interface?&quot;&lt;/code&gt;という質問が表示される。&lt;code&gt;y&lt;/code&gt;を入力すると、&lt;a href=&quot;https://click.palletsprojects.com/en/stable/&quot;&gt;Click&lt;/a&gt;を使ったCLIツールのスターターコードがスクリプトに追加される。&lt;/p&gt;
&lt;p&gt;入力が完了すると以下の3つのファイルが生成される:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pyproject.toml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.gitignore&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;main.py&lt;/code&gt;はCLIツールのスクリプト本体。こちらを編集してツールを作成する。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pyproject.toml&lt;/code&gt;はuv toolとしてインストールするため、ミニマムな内容のみを記述した設定ファイル。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.gitignore&lt;/code&gt;はインストールには不要だが、プロジェクトをGitで管理する場合のために生成している。&lt;/p&gt;
&lt;h2 id=&quot;インストール&quot;&gt;インストール&lt;/h2&gt;
&lt;p&gt;生成したプロジェクトディレクトリを指定して、uvでインストールする:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;uv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; ./your-tool-dir&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -e&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-e&lt;/code&gt;オプションは、編集モードでインストールするためのオプション。これにより、インストールされたツールのソースコードを編集することができる。&lt;/p&gt;
&lt;p&gt;gitリポジトリとしてgithubに公開した場合、以下のコマンドでインストールできる:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;uv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; git+https://github.com/{github-username}/{repo-name}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Gistとして公開する場合は:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; your-tool-dir&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; gist&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; create&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; main.py&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; pyproject.toml&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --description&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;ツールの説明&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Gist自体もGitレポジトリなので、GistのURLを指定すればインストールできる:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;uv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; git+https://gist.github.com/{github-username}/{gist-id}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded></item><item><title>atuin: コマンド履歴管理ツール</title><link>https://blog.kj-dev.net/posts/atuin-setup/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/atuin-setup/</guid><description>コマンド履歴の効率的な管理と検索</description><pubDate>Fri, 18 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://docs.atuin.sh/&quot;&gt;atuin&lt;/a&gt;はRust製のコマンド履歴管理ツール。コマンド履歴をローカルのSQLiteデータベースに保存し、履歴のFuzzy検索や端末間での同期などの機能を提供する。&lt;/p&gt;
&lt;p&gt;普段からzsh組み込みの履歴検索(&lt;code&gt;Control + R&lt;/code&gt;)を使っているが、思い通りにコマンド検索ができないことがあり、atuinを試してみることにした。&lt;/p&gt;
&lt;h2 id=&quot;インストール&quot;&gt;インストール&lt;/h2&gt;
&lt;p&gt;まずはatuinのバイナリをインストールする。以下で簡単にインストールできる:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --proto&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;=https&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --tlsv1.2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -LsSf&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; https://setup.atuin.sh&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;~/.atuin/bin&lt;/code&gt;にバイナリがインストールされる。HomebrewやCargo経由でもインストールできるので、詳細は&lt;a href=&quot;https://docs.atuin.sh/guide/installation/#manual-installation&quot;&gt;公式ドキュメント&lt;/a&gt;を参照。&lt;/p&gt;
&lt;p&gt;次に、atuinを利用するシェルごとに初期化設定を行う必要がある。&lt;/p&gt;
&lt;p&gt;デフォルトのキーバインドでは、上矢印キーで履歴検索画面が表示されるが、無効化したい場合は&lt;code&gt;--disable-up-arrow&lt;/code&gt; 指定する。自分の場合は少々ビジーに感じるので、無効している。&lt;/p&gt;
&lt;p&gt;zshの場合:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;eval &quot;$(atuin init zsh --disable-up-arrow)&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt; &gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; ~/.zshrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;nushellの場合:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; ~/.local/share/atuin/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;atuin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; nu&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --disable-up-arrow&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; save&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; ~/.local/share/atuin/init.nu&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;コマンド履歴のインポート&quot;&gt;コマンド履歴のインポート&lt;/h2&gt;
&lt;p&gt;インストール後の状態では、当然だがコマンド履歴は何も保存されていない。既存のhistoryをatuinにインポートするコマンド&lt;code&gt;atuin import&lt;/code&gt;が用意されているので、これを使って履歴をインポートする。&lt;/p&gt;
&lt;p&gt;zshの場合:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;atuin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; auto&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;nushellの場合:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;atuin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; nushell&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;コマンド履歴の検索&quot;&gt;コマンド履歴の検索&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Control + R&lt;/code&gt;もしくは&lt;code&gt;atuin search -i&lt;/code&gt;で履歴検索のTUIを開くことができる。&lt;/p&gt;
&lt;p&gt;検索ワードを入力すると、Fuzzy検索が行われ、履歴が絞り込まれる。&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/atuin-search.gif&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;atuin-search&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;詳細な検索シンタックスは&lt;a href=&quot;https://docs.atuin.sh/configuration/config/#fuzzy-search-syntax&quot;&gt;公式ドキュメント&lt;/a&gt;に記載されているが、&lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;fzf&lt;/a&gt;のシンタックスをベースとし、完全一致や前方一致、後方一致など、様々な検索方法が利用できる。&lt;/p&gt;
&lt;p&gt;以下は、執筆時点での検索シンタックスの一覧を和訳した表:&lt;/p&gt;
&lt;blockquote&gt;












































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;トークン例&lt;/th&gt;&lt;th&gt;マッチタイプ&lt;/th&gt;&lt;th&gt;説明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;sbtrkt&lt;/code&gt;&lt;/td&gt;&lt;td&gt;あいまい一致&lt;/td&gt;&lt;td&gt;&lt;code&gt;sbtrkt&lt;/code&gt; にマッチするアイテム&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&apos;wild&lt;/code&gt;&lt;/td&gt;&lt;td&gt;完全一致&lt;/td&gt;&lt;td&gt;&lt;code&gt;wild&lt;/code&gt; を含むアイテム&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;^music&lt;/code&gt;&lt;/td&gt;&lt;td&gt;前方完全一致&lt;/td&gt;&lt;td&gt;&lt;code&gt;music&lt;/code&gt; で始まるアイテム&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;.mp3$&lt;/code&gt;&lt;/td&gt;&lt;td&gt;後方完全一致&lt;/td&gt;&lt;td&gt;&lt;code&gt;.mp3&lt;/code&gt; で終わるアイテム&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;!fire&lt;/code&gt;&lt;/td&gt;&lt;td&gt;逆完全一致&lt;/td&gt;&lt;td&gt;&lt;code&gt;fire&lt;/code&gt; を含まないアイテム&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;!^music&lt;/code&gt;&lt;/td&gt;&lt;td&gt;逆前方完全一致&lt;/td&gt;&lt;td&gt;&lt;code&gt;music&lt;/code&gt; で始まらないアイテム&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;!.mp3$&lt;/code&gt;&lt;/td&gt;&lt;td&gt;逆後方完全一致&lt;/td&gt;&lt;td&gt;&lt;code&gt;.mp3&lt;/code&gt; で終わらないアイテム&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;|&lt;/code&gt;は、OR演算子として使える。例えば、次のクエリは「core」で始まり、「go」、「rb」、または「py」のいずれかで終わるエントリにマッチする:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;^core go$ | rb$ | py$&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&quot;enterキーでの実行の無効化&quot;&gt;Enterキーでの実行の無効化&lt;/h2&gt;
&lt;p&gt;デフォルトでは、検索画面でEnterキーを押下すると、選択中のコマンドがすぐに実行される。&lt;/p&gt;
&lt;p&gt;少々危険なので、これは無効化している。atuinのconfigファイル(&lt;code&gt;~/.config/atuin/config.toml&lt;/code&gt;)を編集する:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;toml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# ~/.config/atuin/config.toml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;enter_accept&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#FF5874&quot;&gt; false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;端末間の同期&quot;&gt;端末間の同期&lt;/h2&gt;
&lt;p&gt;atuinは、&lt;a href=&quot;https://docs.atuin.sh/guide/sync/&quot;&gt;端末間の同期機能&lt;/a&gt;も特徴の一つだ。atuinの製作者がホストするサーバーか、セルフホストのサーバーを利用して、端末間で履歴を同期することができる。&lt;/p&gt;
&lt;p&gt;同期機能はまだ試せていない。仕事で利用する場合は少々ハードルが高いが、個人利用であれば試してみてもいいかもしれない。通信はエンドツーエンドで暗号化されているとのこと。&lt;/p&gt;
&lt;p&gt;代替的な端末間の移行方法として、ファイルをコピーする方法もある。&lt;code&gt;atuin info&lt;/code&gt;コマンドで、atuinの設定ファイルやデータベースのパスを確認できるので、ファイル群を端末間でコピーすればOK。ただし、公式のドキュメントにはこの方法について記載がなく、サポートされているわけではないようなので自己責任で行なってほしい。&lt;/p&gt;</content:encoded></item><item><title>SatoriでのOGP画像生成に日本語フォントを使う - astro-paper向けガイド</title><link>https://blog.kj-dev.net/posts/satori-ogp-japanese-font/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/satori-ogp-japanese-font/</guid><description>Satoriの文字化けを解消する</description><pubDate>Tue, 23 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;執筆時点で、このブログは&lt;a href=&quot;https://github.com/satnaing/astro-paper&quot;&gt;&lt;code&gt;astro-paper&lt;/code&gt;&lt;/a&gt;というAstroテンプレートをカスタマイズして作成しています。&lt;code&gt;astro-paper&lt;/code&gt;には、ブログ記事をSNSでシェアしたときに表示されるOGP画像の生成機能も含まれています。&lt;/p&gt;
&lt;p&gt;OGP画像は&lt;a href=&quot;https://github.com/vercel/satori&quot;&gt;&lt;code&gt;satori&lt;/code&gt;&lt;/a&gt;を利用して生成されています。&lt;code&gt;satori&lt;/code&gt;はVercelが提供している、HTMLを画像に変換するためのツールです。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;astro-paper&lt;/code&gt;は非常に便利なテンプレートですが、デフォルトでは日本語非対応の&lt;code&gt;IBM Plex Mono&lt;/code&gt;フォントが指定されているため、日本語テキストを含むOGP画像が正しく表示されません。&lt;/p&gt;
&lt;p&gt;本記事では、この問題を解決し、satoriで日本語フォントを適切に使用する方法を説明します。&lt;/p&gt;
&lt;h2 id=&quot;日本語の文字化け&quot;&gt;日本語の文字化け&lt;/h2&gt;
&lt;p&gt;初期設定の&lt;code&gt;IBM Plex Mono&lt;/code&gt;のまま、日本語を含むテキストをOGP画像に変換すると、日本語に対応していないため、文字化けが発生します。&lt;/p&gt;
&lt;p&gt;先日ポストした&lt;a href=&quot;https://blog.kj-dev.net/blog/cloudflare-pages-direct-upload-github-action/&quot;&gt;「GitHub ActionsからCloudflare pagesにDirect Uploadする」&lt;/a&gt;という記事のOGP画像です:
&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/satori-ogp-japanese-font-failure.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;日本語文字化け&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href=&quot;https://web-toolbox.dev/tools/ogp-checker&quot;&gt;こちらのサイト&lt;/a&gt;でURLを入力してOGP画像を確認できます)&lt;/p&gt;
&lt;p&gt;日本語文字が文字化けしているのがわかります。&lt;/p&gt;
&lt;p&gt;ちなみに、ローカルの環境に日本語フォントがインストールされている場合、フォールバックフォントが使われるため、日本語が文字化けしないことがあるので注意が必要です。自分のmacOSでビルドすると、&lt;code&gt;IBM Plex Mono&lt;/code&gt;を使っていても、日本語が文字化けしませんでした。&lt;/p&gt;
&lt;p&gt;そのため、CI環境でビルドしたOGP画像が文字化けしているかを確認することが重要です。&lt;/p&gt;
&lt;h2 id=&quot;日本語フォントファイルを探す&quot;&gt;日本語フォントファイルを探す&lt;/h2&gt;
&lt;p&gt;今回は日本語対応フォントの&lt;a href=&quot;https://fonts.google.com/noto/specimen/Noto+Sans+JP&quot;&gt;&lt;code&gt;Noto Sans Japanese&lt;/code&gt;&lt;/a&gt;を使います。&lt;/p&gt;
&lt;p&gt;Satoriの設定は簡単で、フォントファイルをロードし、Satoriのコンフィグに追加するだけです。フォントファイルは、&lt;code&gt;.ttf&lt;/code&gt; / &lt;code&gt;.otf&lt;/code&gt; / &lt;code&gt;.woff&lt;/code&gt; 形式に対応しているようです（執筆時点で&lt;code&gt;.woff2&lt;/code&gt;には未対応、公式の&lt;a href=&quot;https://github.com/vercel/satori/blob/main/README.md#fonts&quot;&gt;README参照&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;astro-paper&lt;/code&gt;におけるSatoriの設定箇所は&lt;a href=&quot;https://github.com/satnaing/astro-paper/blob/614e54c2f6a2d672f985c2e4ddbbbb3b5654ad0f/src/utils/generateOgImages.tsx#L25&quot;&gt;こちら&lt;/a&gt;です。&lt;code&gt;Regular&lt;/code&gt;と&lt;code&gt;Bold&lt;/code&gt;の2種類のフォントファイルが必要になります。&lt;/p&gt;
&lt;p&gt;ほとんどのフォントファイルはGoogle Fontsからダウンロードできますが、今回はCDNでホストされているフォントファイルを見つけたので、そちらを使います。CDNを利用することで、ファイルをコードに追加する必要がなくなります（&lt;code&gt;astro-paper&lt;/code&gt;もデフォルトでCDNからフォントファイルを取得しています）。&lt;/p&gt;
&lt;p&gt;CDNはどこでも良いですが、&lt;a href=&quot;https://www.jsdelivr.com/?query=noto%20sans%20jp&quot;&gt;&lt;code&gt;jsDelivr&lt;/code&gt;&lt;/a&gt;を使いました。
“noto sans jp”で検索すると、いくつかパッケージが表示されます:
&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/satori-ogp-japanese-font-jsdeliver.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;jsdeliver noto sans jp&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;パッケージによっては、細かくフォントファイルが分割されている場合があります。分割されている場合、読み込みに手間がかかるので、利用は避けて別のパッケージを探してみることをオススメします。今回は&lt;a href=&quot;https://www.jsdelivr.com/package/npm/@openfonts/noto-sans-jp_japanese&quot;&gt;&lt;code&gt;@openfonts/noto-sans-jp_japanese&lt;/code&gt;&lt;/a&gt;を利用しました。&lt;/p&gt;
&lt;h2 id=&quot;satoriの設定&quot;&gt;Satoriの設定&lt;/h2&gt;
&lt;p&gt;CDNパッケージのページで必要なフォントファイルと対応するURLを確認し、Satoriのconfigに追加します。&lt;/p&gt;
&lt;p&gt;どのファイルをRegularとBoldとして使うかは、ローカルでOG画像を生成して確認しながら決めると良いでしょう。&lt;code&gt;@openfonts/noto-sans-jp_japanese&lt;/code&gt;の場合、ファイル名にフォントのweight（100、200といった数字で、数字が大きいほど太字）が含まれているので、参考にして選びます。&lt;/p&gt;
&lt;p&gt;今回は以下のように設定しました:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Regular: &lt;code&gt;{長いので省略}/files/noto-sans-jp-japanese-300.woff&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Bold: &lt;code&gt;{長いので省略}/files/noto-sans-jp-japanese-500.woff&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;satori&lt;/code&gt;のコンフィグファイル&lt;code&gt;src/utils/generateOgImages.tsx&lt;/code&gt;を以下のように編集します:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;@@ -7,13 +7,13 @@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; const fetchFonts = async () =&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;   // Regular Font&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;   const fontFileRegular = await fetch(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#EF535090&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#EF535090;--shiki-dark-font-style:italic&quot;&gt;    &quot;https://www.1001fonts.com/download/font/ibm-plex-mono.regular.ttf&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478FF&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C5E478FF;--shiki-dark-font-style:italic&quot;&gt;    &quot;https://cdn.jsdelivr.net/npm/@openfonts/noto-sans-jp_japanese@1.44.5/files/noto-sans-jp-japanese-300.woff&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;   );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;   const fontRegular: ArrayBuffer = await fontFileRegular.arrayBuffer();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;   // Bold Font&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;   const fontFileBold = await fetch(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#EF535090&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#EF535090;--shiki-dark-font-style:italic&quot;&gt;    &quot;https://www.1001fonts.com/download/font/ibm-plex-mono.bold.ttf&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478FF&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C5E478FF;--shiki-dark-font-style:italic&quot;&gt;    &quot;https://cdn.jsdelivr.net/npm/@openfonts/noto-sans-jp_japanese@1.44.5/files/noto-sans-jp-japanese-500.woff&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;   );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;   const fontBold: ArrayBuffer = await fontFileBold.arrayBuffer();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;@@ -28,13 +28,13 @@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;   embedFont: true,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;   fonts: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;     {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#EF535090&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#EF535090;--shiki-dark-font-style:italic&quot;&gt;      name: &quot;IBM Plex Mono&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478FF&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C5E478FF;--shiki-dark-font-style:italic&quot;&gt;      name: &quot;NotoSansJP&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;       data: fontRegular,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;       weight: 400,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;       style: &quot;normal&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;     },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;     {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#EF535090&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#EF535090;--shiki-dark-font-style:italic&quot;&gt;      name: &quot;IBM Plex Mono&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478FF&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C5E478FF;--shiki-dark-font-style:italic&quot;&gt;      name: &quot;NotoSansJP&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;       data: fontBold,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;       weight: 600,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;       style: &quot;normal&quot;,&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;実際にデプロイして確認します。修正後のOGP画像:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/satori-ogp-japanese-font-success.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;日本語文字化け解消&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;文字化けが解消され、日本語が正しく表示されました。&lt;/p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;satori&lt;/code&gt;を使ってOGP画像を生成する際、日本語を含むテキストが文字化けする問題を解決するために、日本語フォントを使う方法について説明しました。&lt;/p&gt;
&lt;p&gt;設定自体は簡単ですが、CIとローカルの差分や、日本語対応のフォントを見つけたりするのに時間がかかったので、記録として残しておきます。&lt;/p&gt;</content:encoded></item><item><title>Windows PCをSSHサーバーとして設定する</title><link>https://blog.kj-dev.net/posts/ssh-to-windows/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/ssh-to-windows/</guid><description>macOSから公開鍵認証でSSH接続する</description><pubDate>Tue, 16 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;この記事では、Windows PCをSSHサーバーとして設定し、macOSからリモートでSSH接続する方法を紹介します。&lt;/p&gt;
&lt;p&gt;使っていないWindows PCを自宅のLAN内でサーバーとして活用し、メインで使用しているMacBookからWindowsにSSH接続してリモート作業ができるようにしたいと思い、設定を行ってみました。&lt;/p&gt;
&lt;p&gt;クライアント側はLinux環境でも動作すると思われますが、本記事では検証していません。&lt;/p&gt;
&lt;h2 id=&quot;環境&quot;&gt;環境&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;サーバー: Windows 10 Pro (バージョン 22H2, OS ビルド 19045.3208)&lt;/li&gt;
&lt;li&gt;クライアント: macOS 14.5 (23F79)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;windows側の設定-サーバー側&quot;&gt;Windows側の設定 (サーバー側)&lt;/h2&gt;
&lt;p&gt;まずはパスワード認証でのSSH接続を設定します。秘密鍵を用いての認証は後述します。&lt;/p&gt;
&lt;h3 id=&quot;opensshのインストール&quot;&gt;OpenSSHのインストール&lt;/h3&gt;
&lt;p&gt;WindowsにOpenSSHをインストールします。Windows 10では拡張機能としてGUIからインストールできます。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;[設定] → [システム] → [オプション機能] でOpenSSHを検索&lt;/li&gt;
&lt;li&gt;見つからない場合は [機能の追加] からOpenSSH Serverをインストール&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;sshサービスの設定&quot;&gt;SSHサービスの設定&lt;/h3&gt;
&lt;p&gt;PowerShellを管理者権限で実行し、以下の手順を行います:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;SSH用のポート(22)を開放:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;powershell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;netsh advfirewall firewall add rule name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;sshd&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; dir&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; action&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;allow protocol&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;TCP localport&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;22&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;sshdを起動:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;powershell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#7FDBCAFF&quot;&gt;Start-Service&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; sshd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PC起動時にsshdを自動起動するよう設定:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;powershell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#7FDBCAFF&quot;&gt;Set-Service&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; sshd &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;StartupType Automatic&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;git-bashの導入-オプション&quot;&gt;Git Bashの導入 (オプション)&lt;/h3&gt;
&lt;p&gt;デフォルトのPowerShellではなくGit Bashを使用したい場合:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://gitforwindows.org/&quot;&gt;Git for Windows&lt;/a&gt;からインストーラーをダウンロードしインストール&lt;/li&gt;
&lt;li&gt;管理者権限のPowerShellで以下を実行:
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;powershell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#7FDBCAFF&quot;&gt;New-ItemProperty&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;Path &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;HKLM:\SOFTWARE\OpenSSH&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;Name DefaultShell &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;Value &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;C:\Program Files\Git\bin\bash.exe&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;PropertyType String &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;Force&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
これでSSHログイン時のデフォルトシェルがGit Bashになります。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;接続情報の確認&quot;&gt;接続情報の確認&lt;/h3&gt;
&lt;p&gt;クライアントからSSH接続する際に必要な情報を確認します。ここで確認した情報はクライアント側で使用します。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;IPアドレスの確認:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;powershell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;ipconfig&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ユーザー名の確認:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;powershell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;System.Security.Principal.WindowsIdentity&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;]::GetCurrent().Name&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;クライアントからの接続&quot;&gt;クライアントからの接続&lt;/h3&gt;
&lt;p&gt;macOSから以下のコマンドで接続:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; {serverのユーザー名}@{serverのIPアドレス}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意: ユーザー名にバックスラッシュ&lt;code&gt;\&lt;/code&gt;を含む場合、macOSからSSHする際は&lt;code&gt;/&lt;/code&gt;に読み替えてください。&lt;/p&gt;
&lt;p&gt;接続がうまくいかない場合は、&lt;code&gt;-vvv&lt;/code&gt;オプションを付けてログを確認できます。&lt;/p&gt;
&lt;h2 id=&quot;公開鍵認証の設定&quot;&gt;公開鍵認証の設定&lt;/h2&gt;
&lt;p&gt;より安全でパスワード入力が不要な、公開鍵認証の設定方法を説明します。&lt;/p&gt;
&lt;h3 id=&quot;クライアント側-macos&quot;&gt;クライアント側 (macOS)&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;公開鍵を生成（多くの記事が存在するので、方法は割愛）&lt;/li&gt;
&lt;li&gt;生成した公開鍵をサーバーに送信:
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;scp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; ~/.ssh/your_keyfile_ed25519.pub&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; {serverのユーザー名}@{serverのIPアドレス}:~/.ssh/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;サーバー側-windows&quot;&gt;サーバー側 (Windows)&lt;/h3&gt;
&lt;p&gt;ここからの設定で自分は詰まってしまい、時間がかかってしまいました。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;(https://stackoverflow.com/questions/16212816/setting-up-openssh-for-windows-using-public-key-authentication)&quot;&gt;こちら&lt;/a&gt;のStackOverflowの回答がとても参考になったので、もし下記の手順で詰まったら参照してみてください。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;クライアントから送信した公開鍵ファイルのリネーム:
&lt;code&gt;~/.ssh/your_keyfile_ed25519.pub&lt;/code&gt; → &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt;のパーミッション設定変更:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;権限の継承をOFF&lt;/li&gt;
&lt;li&gt;SYSTEM, USER(Windowsのユーザー)以外の権限を削除&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;C:\ProgramData\ssh\sshd_config&lt;/code&gt;の編集:&lt;/p&gt;
&lt;p&gt;公開鍵認証を有効化し、パスワード認証を無効化します:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#EF535090&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#EF535090;--shiki-dark-font-style:italic&quot;&gt;#PubkeyAuthentication yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478FF&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C5E478FF;--shiki-dark-font-style:italic&quot;&gt;PubkeyAuthentication yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#EF535090&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#EF535090;--shiki-dark-font-style:italic&quot;&gt;#PasswordAuthentication yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478FF&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C5E478FF;--shiki-dark-font-style:italic&quot;&gt;PasswordAuthentication no&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以下の&lt;code&gt;Match Group administrators ...&lt;/code&gt;で始まる2行がコメントアウトされていない場合、コメントアウトしてください:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#EF535090&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#EF535090;--shiki-dark-font-style:italic&quot;&gt;Match Group administrators&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#EF535090&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#EF535090;--shiki-dark-font-style:italic&quot;&gt;       AuthorizedKeysFile __PROGRAMDATA__/ssh/   administrators_authorized_keys&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478FF&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C5E478FF;--shiki-dark-font-style:italic&quot;&gt;#Match Group administrators&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478FF&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C5E478FF;--shiki-dark-font-style:italic&quot;&gt;#       AuthorizedKeysFile __PROGRAMDATA__/ssh/   administrators_authorized_keys&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;補足:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;C:\ProgramData&lt;/code&gt;はエクスプローラ上で&lt;code&gt;C&lt;/code&gt;ドライブを開いても表示されないかもしれませんが、アドレスバーに直接打ち込めば開けるはずです。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C:\Windows\System32\OpenSSH&lt;/code&gt;にも似たファイル&lt;code&gt;sshd_config_default&lt;/code&gt;がありますが、そちらをいじっても設定は反映されません。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;sshdの再起動:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;powershell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#7FDBCAFF&quot;&gt;Restart-Service&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; sshd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;クライアントからの接続-1&quot;&gt;クライアントからの接続&lt;/h2&gt;
&lt;p&gt;macOSから以下のコマンドで接続:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; {serverのユーザー名}@{serverのIPアドレス}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;パスワードを入力せずに接続できれば成功です。&lt;/p&gt;
&lt;h2 id=&quot;トラブルシューティング&quot;&gt;トラブルシューティング&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;サーバー側でsshの設定が反映されない場合は&lt;code&gt;Restart-Service sshd&lt;/code&gt;を実行するかPCを再起動してください&lt;/li&gt;
&lt;li&gt;クライアント側で&lt;a href=&quot;https://www.warp.dev/&quot;&gt;Warp&lt;/a&gt;をターミナルで使用している場合、ssh接続がすぐに切断されることがあります。Warp SSH Wrapperを無効化してみてください:
&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/disable-warp-ssh-wrapper.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;WarpのSSH Wrapperを無効化する&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/li&gt;
&lt;li&gt;SSH接続時に&lt;code&gt;-vvv&lt;/code&gt;オプションを付けてログを確認することで、問題の特定ができるかもしれません&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;/h2&gt;
&lt;p&gt;Windows PCをSSHサーバーとして設定し、macOSからリモートでSSH接続する方法を解説しました。&lt;/p&gt;
&lt;p&gt;本来はTmuxを使ってセッションが切れてもプロセスを継続できるようにしたかったのですが、Git Bashでの設定が上手くいかず、今回は断念しました。いずれ再トライしてみたいと思います。&lt;/p&gt;</content:encoded></item><item><title>WeekNotes: 2024-07-11</title><link>https://blog.kj-dev.net/posts/weeknote-20240711/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/weeknote-20240711/</guid><description>LLMs全般, GitHub Copilot, Claude, その他の技術トピック</description><pubDate>Thu, 11 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;今週、気になった話題&lt;/p&gt;
&lt;h2 id=&quot;llms全般&quot;&gt;LLMs全般&lt;/h2&gt;
&lt;h3 id=&quot;simon-willison氏がai-engineer-worlds-fairで新たなkeynoteスピーチ&quot;&gt;&lt;a href=&quot;https://simonwillison.net/2024/Jun/27/ai-worlds-fair/&quot;&gt;Simon Willison氏がAI Engineer World’s Fairで新たなKeyNoteスピーチ&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;一見の価値あり
&lt;ul&gt;
&lt;li&gt;GPT-4oの一強体制は崩れつつある&lt;/li&gt;
&lt;li&gt;Gemini FlashはGPT-3.5より格段に優れ、かつ安い&lt;/li&gt;
&lt;li&gt;など&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;softbankymobilelinemoユーザーは1年間perplexity-aiが無料で利用可能&quot;&gt;&lt;a href=&quot;https://www.softbank.jp/mobile/service/perplexity-ai/&quot;&gt;SoftBank、Y!mobile、LINEMOユーザーは1年間Perplexity AIが無料で利用可能&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;SoftBank、Y!mobile、LINEMOユーザーなら絶対に使ってみるべし&lt;/li&gt;
&lt;li&gt;2025/6/18まで無料&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;github-copilot&quot;&gt;GitHub Copilot&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/changelog/2024-07-05-github-copilot-enterprise-on-gpt-4o/&quot;&gt;Copilot EnterpriseでGPT-4oが利用可能に&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/changelog/2024-07-09-copilot-knowledge-bases-in-visual-studio-preview/&quot;&gt;Copilot EnterpriseでCopilot Knowledge Basesからの情報取得がプレビューに&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/enterprise-cloud@latest/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-github-copilot-features-in-your-organization/managing-copilot-knowledge-bases&quot;&gt;Copilot Knowledge Bases&lt;/a&gt;は、1つ以上のGitHubリポジトリからなる情報源&lt;/li&gt;
&lt;li&gt;組織のオーナーがKnowledge Basesを設定できる
&lt;ul&gt;
&lt;li&gt;組織内でKnowledge Basesの内容は共通&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;claude&quot;&gt;Claude&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://x.com/alexalbert__/status/1810699033524195673&quot;&gt;Artifactsのシェアが可能に&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;other-tech-topics&quot;&gt;Other Tech Topics&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://x.com/8teAPi/status/1809664298714820719&quot;&gt;AIによる顔変換&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;なりたい顔になれる世界が来る？&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://duckdb.org/2024/07/05/community-extensions.html&quot;&gt;DuckDBがコミュニティ拡張機能をサポート&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=40878765&quot;&gt;Hacker Newsの面白いコメント&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;作ったシステムで彼女が解雇になったお話&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;my-blog-posts&quot;&gt;My Blog Posts&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../cloudflare-pages-direct-upload-github-action&quot;&gt;GitHub ActionsからCloudflare Pagesに直接アップロードする&lt;/a&gt; (2024/7/6)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../setup-changeset&quot;&gt;Changesets: バージョン・リリース管理ツールの設定方法&lt;/a&gt; (2024/7/7)&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Changesets: バージョン・リリース管理ツールの設定方法</title><link>https://blog.kj-dev.net/posts/setup-changeset/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/setup-changeset/</guid><description>Changesetsでバージョン管理を効率的に</description><pubDate>Sun, 07 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;changesetsとは&quot;&gt;Changesetsとは&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/changesets/changesets&quot;&gt;Changesets&lt;/a&gt;は、Svelte.jsのリポジトリでも採用されているバージョン管理ツールです。Changesets自体はnpmパッケージとして提供されており、Node.jsプロジェクトの管理を行うためのCLIツールとして利用できます。&lt;/p&gt;
&lt;p&gt;Changesetsには以下の主要機能があります:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PR単位またはコミット単位で変更メッセージをMarkdownファイルで生成し管理（Gitにコミット）&lt;/li&gt;
&lt;li&gt;Semantic Versioningに基づいたタグのバンプ（生成したMarkdownはバンプ時に自動削除）&lt;/li&gt;
&lt;li&gt;Changelogの自動生成&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Svelte.jsの&lt;a href=&quot;https://github.com/sveltejs/svelte/releases&quot;&gt;Releases&lt;/a&gt;を見ると、Semverに基づいたリリースがなされ、リリースノートでは各PRへのリンクが付いていて、とても見やすくなっています。これはChangesetsを利用して作成されています。&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/sveltejs-releasenotes.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;svelteのリリース&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;リリースプロセスにChangesetsを組み込むには、&lt;a href=&quot;https://github.com/changesets/action&quot;&gt;&lt;code&gt;changesets/action&lt;/code&gt;&lt;/a&gt;というGitHub Actionsを利用できます。&lt;/p&gt;
&lt;p&gt;また、&lt;a href=&quot;https://github.com/apps/changeset-bot&quot;&gt;changeset-bot&lt;/a&gt;というGitHub Appを導入することで、Pull RequestにChangesetsが適切に適用されているかを自動でチェックすることもできます。&lt;/p&gt;
&lt;p&gt;本記事では、Changesetsのインストールから、GitHub Actions、GitHub botの設定方法について解説します。&lt;/p&gt;
&lt;h2 id=&quot;changesetsの設定&quot;&gt;Changesetsの設定&lt;/h2&gt;
&lt;h3 id=&quot;1-changesetsのインストールと初期設定&quot;&gt;1. Changesetsのインストールと初期設定&lt;/h3&gt;
&lt;p&gt;まず、Changesetsのコマンドラインインターフェース（CLI）をインストールします:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;pnpm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; @changesets/cli&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次に、Changesetsの初期設定を行います:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;pnpm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; changeset&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; init&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.changeset/&lt;/code&gt;ディレクトリが作成され、設定ファイルが生成されます。生成されたファイルはコミットしておきます:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;chore: Changesetsの初期設定を追加&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-packagejsonの更新&quot;&gt;2. package.jsonの更新&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;の&lt;code&gt;scripts&lt;/code&gt;セクションに以下のコマンドを追加します:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;&quot;scripts&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478FF&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C5E478FF;--shiki-dark-font-style:italic&quot;&gt;   &quot;changeset&quot;: &quot;changeset&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478FF&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C5E478FF;--shiki-dark-font-style:italic&quot;&gt;   &quot;tag&quot;: &quot;changeset tag&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;1つ目の&lt;code&gt;pnpm changeset&lt;/code&gt;は、新しいChangesetを追加するためのコマンドです。ローカルで変更を行った場合、このコマンドを実行して変更内容を記録します。&lt;/p&gt;
&lt;p&gt;2つ目の&lt;code&gt;pnpm tag&lt;/code&gt;は、Changesetを元にバージョンを更新するためのコマンドです。後述するGitHub Actionsで使用します。&lt;/p&gt;
&lt;h3 id=&quot;3-changelogのカスタマイズ&quot;&gt;3. Changelogのカスタマイズ&lt;/h3&gt;
&lt;p&gt;GitHubリポジトリを使用している場合、&lt;a href=&quot;https://github.com/svitejs/changesets-changelog-github-compact&quot;&gt;&lt;code&gt;changesets-changelog-github-compact&lt;/code&gt;&lt;/a&gt;プラグインを導入すると、より洗練されたChangelogを生成できます。&lt;/p&gt;
&lt;p&gt;Svelte.jsでも利用されており、必須ではありませんが導入をおすすめします。&lt;/p&gt;
&lt;p&gt;プラグインのインストール:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;pnpm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; @svitejs/changesets-changelog-github-compact&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次に、&lt;code&gt;.changeset/config.json&lt;/code&gt;を編集してChangelogの設定を変更します:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#EF535090&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#EF535090;--shiki-dark-font-style:italic&quot;&gt;  &quot;changelog&quot;: &quot;@changesets/cli/changelog&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478FF&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C5E478FF;--shiki-dark-font-style:italic&quot;&gt;  &quot;changelog&quot;: [&quot;@svitejs/changesets-changelog-github-compact&quot;, { &quot;repo&quot;: &quot;your-username/your-repo&quot; }],&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;your-username/your-repo&lt;/code&gt;は、実際のGitHubリポジトリのパスに置き換えてください。&lt;/p&gt;
&lt;p&gt;プラグインの設定は以上で完了です。
その他のプラグインに関する詳細は&lt;a href=&quot;https://github.com/svitejs/changesets-changelog-github-compact/blob/main/packages/changesets-changelog-github-compact/README.md&quot;&gt;こちら&lt;/a&gt;を参照してください。&lt;/p&gt;
&lt;h2 id=&quot;github-actionsの設定&quot;&gt;GitHub Actionsの設定&lt;/h2&gt;
&lt;p&gt;GitHub Actionsで&lt;code&gt;changesets/action&lt;/code&gt;を使用してリリースプロセスを自動化します。様々なワークフローの設定パターンが存在するので、詳細は&lt;a href=&quot;https://github.com/changesets/action?tab=readme-ov-file#example-workflow&quot;&gt;README&lt;/a&gt;を参照してください。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;changesets/action&lt;/code&gt;でnpmへのパッケージのpublishまで行うことができますが、npmへのpublish以外のデプロイも柔軟に設定できます。&lt;/p&gt;
&lt;p&gt;以下は、Changesetsでのnpmへのpublishは行わず、独自のデプロイを実施するGitHub Actionsの設定例です:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;yml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#FF5874&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  push&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;    branches&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# リリースブランチを指定&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  release&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;    runs-on&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; ubuntu-latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;    permissions&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      contents&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; write&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # Changesets to create releases&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      pull-requests&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; write&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # Changesets to create PRs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;      #deployments: write # uncomment if your deploy task creates deployments&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; actions/checkout@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Use Node.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; actions/setup-node@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; pnpm/action-setup@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Install pnpm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          version&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt; 8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          run_install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#FF5874&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Get pnpm store directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; pnpm-cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        shell&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;          echo &quot;STORE_PATH=$(pnpm store path)&quot; &gt;&gt; $GITHUB_OUTPUT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; actions/cache@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Setup pnpm cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          key&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;${{ runner.os }}-pnpm-store-${{ hashFiles(&apos;**/pnpm-lock.yaml&apos;) }}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;${{ steps.pnpm-cache.outputs.STORE_PATH }}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          restore-keys&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;            &quot;${{ runner.os }}-pnpm-store-&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Install dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; pnpm install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Run Changesets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; changesets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; changesets/action@v1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          title&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Update version&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;          # just needs to echo `New tag: @somename/{pkgName}}@{tagName}` for changesets action to create GitHub release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          publish&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; pnpm tag&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          GITHUB_TOKEN&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; ${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Build and Deploy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; steps.changesets.outputs.hasChangesets == &apos;false&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # リリース時のみ実行&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;          pnpm build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;          # ここにデプロイ用のコマンドを追加&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Run Changesets&lt;/code&gt;タスクで、&lt;code&gt;changesets/action&lt;/code&gt;を実行しています。
&lt;code&gt;changesets/action&lt;/code&gt;は、2通りの動作を実施します。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt;ブランチで&lt;code&gt;.changesets/&lt;/code&gt;に新しいChangesetがpushされた場合&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;main&lt;/code&gt;ブランチに対してリリースPull Requestを作成/更新します。&lt;/p&gt;
&lt;p&gt;リリースPull Requestの差分は:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;package.jsonのバージョンアップ&lt;/li&gt;
&lt;li&gt;Changelogの更新&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.changesets/&lt;/code&gt;にあるChangesetsの削除&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考としてSvelte.jsの&lt;a href=&quot;https://github.com/sveltejs/svelte/pull/11925/files&quot;&gt;リリースPull Request&lt;/a&gt;を見てみてください。&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;リリースPull Requestのマージによって&lt;code&gt;main&lt;/code&gt;ブランチがpushされた場合&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Changesetsによってリリース処理を行います:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;with.publishに指定したコマンド&lt;code&gt;pnpm tag&lt;/code&gt;が実行され、タグを作成します。&lt;/li&gt;
&lt;li&gt;作成されたタグに対応するGitHub Releaseを作成します。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Build and Deploy&lt;/code&gt;タスクは、リリースPull Requestがマージされた場合にのみ実行されます。&lt;/p&gt;
&lt;h2 id=&quot;github-botの設定&quot;&gt;GitHub botの設定&lt;/h2&gt;
&lt;p&gt;Changeset botを導入することで、Pull RequestにChangesetsが適切に適用されているかを自動でチェックできます。設定手順は以下の通りです:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/apps/changeset-bot&quot;&gt;Changeset bot&lt;/a&gt;のページにアクセスします。&lt;/li&gt;
&lt;li&gt;“Install”ボタンをクリックし、指示に従ってリポジトリに対してbotを有効化します。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;changesetsの使用方法&quot;&gt;Changesetsの使用方法&lt;/h2&gt;
&lt;p&gt;ここまでで、Changesetsの設定は完了です！&lt;/p&gt;
&lt;p&gt;開発時に、適宜&lt;code&gt;pnpm changeset&lt;/code&gt;コマンドを実行してChangesetを追加します。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;pnpm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; changeset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# プロンプトに従って変更内容を入力&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# ./changesetに変更内容を記録したMarkdownファイルが生成されるので、コミットする&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;feat: 新機能を追加&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;次回リリースまでの変更内容が&lt;code&gt;.changeset/&lt;/code&gt;に記録されていきます。
あとはこれらの変更を&lt;code&gt;main&lt;/code&gt;ブランチにマージすれば、リリースPull Requestが作成されます。&lt;/p&gt;
&lt;p&gt;リリース時には、リリースPull Requestをマージするだけで、バージョンアップとリリースノートの作成が自動で行われます。&lt;/p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;/h2&gt;
&lt;p&gt;Changesetsを導入することで、タグ、Changelog、リリース作成が大幅に効率化されます。
これらを手動で行うことを手間に感じている場合は、ぜひChangesetsを導入してみてください。&lt;/p&gt;</content:encoded></item><item><title>GitHub ActionsからCloudflare pagesにDirect Uploadする</title><link>https://blog.kj-dev.net/posts/cloudflare-pages-direct-upload-github-action/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/cloudflare-pages-direct-upload-github-action/</guid><description>GithubとCloudflareのセットアップ手順</description><pubDate>Sat, 06 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;GitHub ActionsからCloudflare Pagesにデプロイする方法について、何度か設定しているものの、いつも忘れてしまうので、記録しておきます。&lt;/p&gt;
&lt;p&gt;参考資料:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.cloudflare.com/pages/get-started/direct-upload/&quot;&gt;Direct Uploadの公式ドキュメント&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zenn.dev/nwtgck/articles/1fdee0e84e5808&quot;&gt;Direct Uploadの詳細な設定方法についての記事&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cloudflare Pagesへのデプロイ方法には、他にも&lt;a href=&quot;https://developers.cloudflare.com/pages/get-started/git-integration/&quot;&gt;Git Integration&lt;/a&gt;があります。&lt;/p&gt;
&lt;p&gt;GitHubのリポジトリと連携するには一見こちらのほうが適していそうですが、デプロイ時の細かい処理を組むことが難しいため、ここで紹介する&lt;code&gt;Direct Upload&lt;/code&gt;を使うことをおすすめします。&lt;/p&gt;
&lt;p&gt;前提条件:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare Pagesのアカウントを作成済みであること&lt;/li&gt;
&lt;li&gt;パッケージマネージャーに&lt;code&gt;pnpm&lt;/code&gt;を使用しているため、以下のコマンド例も&lt;code&gt;pnpm&lt;/code&gt;を使用しています。&lt;code&gt;npm&lt;/code&gt;や&lt;code&gt;yarn&lt;/code&gt;の場合は適宜読み替えてください。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;pagesプロジェクトを作成する&quot;&gt;Pagesプロジェクトを作成する&lt;/h2&gt;
&lt;p&gt;まず、&lt;a href=&quot;https://developers.cloudflare.com/workers/wrangler/install-and-update/&quot;&gt;wrangler&lt;/a&gt;というCloudflareのCLIツールをインストールします。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;pnpm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; wrangler&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --save-dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;インストールできたら、バージョンを確認します。
v3系のバージョンが表示されればOKです:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;pnpx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; wrangler&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -v&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;wranglerを使ってPagesのプロジェクトを作成します:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;pnpx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; wrangler&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; pages&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; project&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; create&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ブラウザが開いてOAuth認証を求められるので、認証を行います。&lt;/p&gt;
&lt;p&gt;プロンプトで入力を求められるので、適宜入力します:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;✔ Enter the name of your new project:&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare Pagesのプロジェクト名。GitHubのリポジトリ名と同じにするとわかりやすいです。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;✔ Enter the production branch name:&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare Pagesのプロジェクト内のプロダクションブランチ名。GitHubのプロダクションブランチ（mainブランチ）と同じにします。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;wranglerを使って作成したプロジェクトを確認できます:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;pnpx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; wrangler&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; pages&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; project&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;github-actionsを設定する&quot;&gt;GitHub Actionsを設定する&lt;/h2&gt;
&lt;p&gt;GitHub Actionsの設定ファイルを作成して、Cloudflare PagesにデプロイするActionを追加します。&lt;/p&gt;
&lt;p&gt;適宜、設定値を変更して以下の設定ファイルをリポジトリに作成します:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;yml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# `.github/workflows/release.yml`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#FF5874&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  push&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;    branches&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  workflow_dispatch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  release&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;    runs-on&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; ubuntu-latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;    permissions&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      contents&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; read&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      deployments&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; write&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # cloudflare/pages-action@1 でデプロイメントを作成するために必要&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; actions/checkout@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Use Node.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; actions/setup-node@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; pnpm/action-setup@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Install pnpm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          version&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt; 8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          run_install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#FF5874&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Get pnpm store directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; pnpm-cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        shell&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;          echo &quot;STORE_PATH=$(pnpm store path)&quot; &gt;&gt; $GITHUB_OUTPUT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; actions/cache@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Setup pnpm cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          key&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;${{ runner.os }}-pnpm-store-${{ hashFiles(&apos;**/pnpm-lock.yaml&apos;) }}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;${{ steps.pnpm-cache.outputs.STORE_PATH }}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          restore-keys&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;            &quot;${{ runner.os }}-pnpm-store-&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Install dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; pnpm install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Build production bundle&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; pnpm build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Publish to Cloudflare Pages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; cloudflare/pages-action@1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          accountId&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;${{ secrets.CLOUDFLARE_ACCOUNT_ID }}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # CloudflareのアカウントID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          apiToken&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;${{ secrets.CLOUDFLARE_API_TOKEN }}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # CloudflareのAPIトークン&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          projectName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; your-project-name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # 先ほど作成したCloudflare Pagesのプロジェクト名&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          directory&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; ./dist&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # ビルドしたファイルが入っているディレクトリ&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          gitHubToken&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; ${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # GitHub Actionsのdeploymentsを作成する場合に必要&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;          # オプション: 公開するブランチを切り替えます。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;          # デフォルトではこのワークフローをトリガーしたブランチになります&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          branch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;          # オプション: Wranglerのバージョンを変更します。特定のバージョンや&apos;beta&apos;などのタグを指定できます&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          wranglerVersion&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Actionsで参照している&lt;code&gt;secrets&lt;/code&gt;は、GitHubのリポジトリの&lt;code&gt;Settings&lt;/code&gt; -&gt; &lt;code&gt;Secrets&lt;/code&gt;で登録できます。&lt;/p&gt;
&lt;p&gt;アカウントIDの調べ方・トークン発行の方法は、冒頭に記載したブログ記事が参考になります:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://arc.net/l/quote/nhebgjot&quot;&gt;CloudflareのアカウントIDの調べ方&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zenn.dev/nwtgck/articles/1fdee0e84e5808#cloudflare%E3%81%AE%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%AE%E4%BD%9C%E6%88%90&quot;&gt;CloudflareのAPIトークンの作成方法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上で設定は完了です。あとは&lt;code&gt;main&lt;/code&gt;ブランチにプッシュするか、Actionsの&lt;code&gt;workflow_dispatch&lt;/code&gt;から手動で実行すると、Cloudflare Pagesにデプロイされます。&lt;/p&gt;</content:encoded></item><item><title>Github Actionsから別のリポジトリにコミットする</title><link>https://blog.kj-dev.net/posts/write-another-repo-from-gh-action/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/write-another-repo-from-gh-action/</guid><description>PATを使ってコミットする</description><pubDate>Sat, 13 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;あるGithubレポジトリのGithub Actionsから、別のGithubレポジトリに変更をコミットする方法について。&lt;/p&gt;
&lt;p&gt;ワークフローの流れとしては、以下になる:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;まずコミットをPushするレポジトリをCloneする&lt;/li&gt;
&lt;li&gt;何らかの変更を加える&lt;/li&gt;
&lt;li&gt;変更をコミットしてPushする&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;サンプルのワークフロー定義は以下。
Push先のレポジトリ名は&lt;code&gt;yyy&lt;/code&gt;とする:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;yml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; Update antoher repo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#FF5874&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  workflow_dispatch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  schedule&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;cron&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;49 0 */2 * *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # once two days for example&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  update-another-repo&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;    runs-on&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; ubuntu-latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;      # may be some scripts here&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; checkout yyy repo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        uses&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; actions/checkout@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          repository&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;xxx/yyy&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          ref&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;yyy&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          token&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;${{ secrets.PAT_WRITE_YYY }}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          persist-credentials&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#FF5874&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; make change to yyy repo&apos;s file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;          make some-change # just example, apply change to files in yyy repo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt; commit to yyy repo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;          git config --local user.email &quot;action@github.com&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;          git config --local user.name &quot;GitHub Action&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;          cd yyy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;          git add . -A&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;          (git commit -m &quot;Update from github actions&quot; &amp;#x26;&amp;#x26; git push) || echo &quot;No changes to commit&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここで、&lt;code&gt;${{ secrets.PAT_WRITE_YYY }}&lt;/code&gt;は、&lt;code&gt;yyy&lt;/code&gt;レポジトリにPushするためのPAT。&lt;/p&gt;
&lt;p&gt;PATを発行するには、Githubアカウントにログインし、Settingsから、Developer settings &gt; Personal access tokens(Fine-grained)に行き、&lt;code&gt;yyy&lt;/code&gt;レポジトリにContents: Write権限を付与する(画像内の上の赤枠):&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/fine-grained-pat.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;PATのScopeを設定する&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;自動でMetadataのRead権限も付与されるが、必須で付随するものなのでこのままでOK（画像内の下の赤枠）&lt;/p&gt;
&lt;p&gt;PATを発行したら、&lt;code&gt;yyy&lt;/code&gt;レポジトリのSettings &gt; Secrets and Variables &gt; Actionsを開き、secretsにPATを登録する。&lt;/p&gt;
&lt;p&gt;ちなみにPATがないと、Pushする権限がないため、以下エラーになる。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;log&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;remote: Permission to &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;xxx.git&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; denied to github-actions[bot].&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;fatal: unable to access &lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;&apos;https://github.com/xxx/&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;: The requested URL returned &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-weight:bold;--shiki-dark:#ECC48D;--shiki-dark-font-weight:inherit&quot;&gt;error:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt; 403&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded></item><item><title>AWSアカウント間でのS3 to S3ファイルコピー</title><link>https://blog.kj-dev.net/posts/s3-to-s3-copy/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/s3-to-s3-copy/</guid><description>S3toS3のデータ連携のステップ</description><pubDate>Thu, 04 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;自分のAWSアカウント内のS3から、別アカウントのS3へファイルをコピーする機会があったので方法を残しておく。&lt;/p&gt;
&lt;p&gt;今回は送信元アカウントのIAMユーザーに対して、送信先アカウントで権限を付与してもらい、このIAMユーザーを使ってファイルをコピーする方法を取った。&lt;/p&gt;
&lt;p&gt;内容としてはこちらの記事にも詳しく説明されている:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://repost.aws/knowledge-center/copy-s3-objects-account&quot;&gt;https://repost.aws/knowledge-center/copy-s3-objects-account&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;準備&quot;&gt;準備&lt;/h2&gt;
&lt;p&gt;まず、送信先のアカウントの管理者から、送信先のバケット名、バケット内のどのPrefixにファイルをコピーするのかを確認しておく。ここでは仮に&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;送信先バケット名: &lt;code&gt;bucket-to&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;送信先Prefix: &lt;code&gt;copy/to/here/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;とする。&lt;/p&gt;
&lt;p&gt;*実務的には、1回限りの連携と思っても、実際には何度かデータ再送信することもある。なのでPrefixは適宜ネームスペースを切っておくと良い。例えば、&lt;code&gt;copy/here/${送信日}/${ファイルバージョン名}/&lt;/code&gt;みたいに。&lt;/p&gt;
&lt;p&gt;送信元については、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;送信元バケット名: &lt;code&gt;bucket-from&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;送信元Prefix: &lt;code&gt;copy/from/here&lt;/code&gt; (ココにコピーしたいファイルを置いている)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;とする。&lt;/p&gt;
&lt;h2 id=&quot;送信元-iamユーザー作成と権限付与&quot;&gt;送信元: IAMユーザー作成と権限付与&lt;/h2&gt;
&lt;p&gt;次に、ファイルを送信するためのIAMユーザーを作成する。&lt;/p&gt;
&lt;p&gt;適当な名称でIAMユーザーを払い出し、以下のPolicyをアタッチする。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  &quot;Version&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;2012-10-17&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  &quot;Statement&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Effect&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;Allow&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Action&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;s3:ListBucket&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;s3:GetObject&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;s3:GetObjectTagging&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Resource&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;arn:aws:s3:::bucket-from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;arn:aws:s3:::bucket-from/copy/from/here/*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Effect&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;Allow&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Action&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;s3:ListBucket&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;s3:PutObject&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;s3:PutObjectAcl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Resource&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;arn:aws:s3:::bucket-to&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;arn:aws:s3:::bucket-to/copy/to/here/*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここで、参考記事にも記載されているが、&lt;code&gt;s3:GetObjectTagging&lt;/code&gt;については、送信元のS3バケットでバージョニングを有効化している場合は必要となる。その他、権限でエラーが出た場合の対応についても参考記事に詳しく載っている。&lt;/p&gt;
&lt;p&gt;発行したらIAMユーザーのARNを送信先アカウントの管理者に連携する。
ARNはこのような形式になるはず: &lt;code&gt;arn:aws:iam::123456789:user/copy-user&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&quot;送信先-バケットの権限設定&quot;&gt;送信先: バケットの権限設定&lt;/h2&gt;
&lt;p&gt;送信先のバケットのS3 Object OwnerShipをbucket owner prefferedに設定する。
これで&lt;code&gt;bucket-owner-full-control&lt;/code&gt;オプション付きでUploadされたオブジェクトは、送信先アカウントの所有となる。&lt;/p&gt;
&lt;p&gt;次に、送信先バケットのバケットポリシーを設定する。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  &quot;Version&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;2012-10-17&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  &quot;Id&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;Policy123456789&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  &quot;Statement&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Sid&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;Stmt123456789&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Effect&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;Allow&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Principal&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        &quot;AWS&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;arn:aws:iam::123456789:user/copy-user&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      }&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Action&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;s3:PutObject&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Resource&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;arn:aws:s3:::bucket-to/*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Condition&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        &quot;StringEquals&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;          &quot;s3:x-amz-acl&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;bucket-owner-full-control&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Sid&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;Stmt123456789&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Effect&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;Allow&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Principal&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;        &quot;AWS&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;arn:aws:iam::123456789:user/copy-user&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      }&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Action&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;s3:ListBucket&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;      &quot;Resource&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#C789D6&quot;&gt;arn:aws:s3:::bucket-to&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここでも、先ほどのアカウントと同様、ObjectTaggingなど必要な権限は環境によって異なる可能性があるので、適宜修正する。&lt;/p&gt;
&lt;h2 id=&quot;送信元-ファイル送信&quot;&gt;送信元: ファイル送信&lt;/h2&gt;
&lt;p&gt;以上で設定は完了したので、ファイルを送信できる。&lt;/p&gt;
&lt;p&gt;自分のケースではショットでの対応だったので、作業PCからaws cliを叩いて実行した。適宜キーを発行してaws cliでの認証を通しておく。今回は&lt;code&gt;--profile copy-user&lt;/code&gt;に設定したものとする。&lt;/p&gt;
&lt;p&gt;まずは実行前に&lt;code&gt;--dryrun&lt;/code&gt;を使ってコマンドを確認するのがおすすめ。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; s3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --dryrun&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt;   --profile&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; copy-user&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt;   --recursive&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt;   --expected-size&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt; 107374182400&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt;   --acl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; bucket-owner-full-control&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#F78C6C&quot;&gt; \\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt;      s3://bucket-from/copy/from/here/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; s3://bucket-to/copy/to/here/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここで、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--expected-size 107374182400&lt;/code&gt; は50GiB以上の大きなファイルをコピー際に必要なオプション（&lt;a href=&quot;https://ebc-2in2crc.hatenablog.jp/entry/2021/07/13/230906&quot;&gt;参考&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--acl bucket-owner-full-control&lt;/code&gt; は前述の通りコピーしたオブジェクトのOwnerを送信先アカウントとするために必要なオプション&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;dryrun結果に問題がなければ、&lt;code&gt;--dryrun&lt;/code&gt;オプションを消して実行する。
データ量が多い場合は、かなり時間がかかることもあるので、作業PC上で実行する際はtmuxを活用すると、PCがスリープしてもバックグランドで実行を継続してくれる。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;tmux&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; s3-operation&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;自分の場合は、tmuxで実行したが、社内VPNが途中で切れてしまってErrorになってしまった。可能であればVPNは最初から切っておくのが良さそうだ。&lt;/p&gt;
&lt;p&gt;送信が完了したら、最後に念の為、ファイル数とサイズが一致するか確認しておくと良いだろう。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# ファイル数の一致確認&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; s3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; ls&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --profile&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; copy-user&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --recursive&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; s3://bucket-from/copy/from/here/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; wc&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -l&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; s3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; ls&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --profile&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; copy-user&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --recursive&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; s3://bucket-to/copy/to/here/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; wc&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; -l&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# ファイルサイズの一致確認&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; s3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; ls&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --profile&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; copy-user&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --recursive&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --summarize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; s3://bucket-from/copy/from/here/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Total Size&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; s3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; ls&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --profile&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; copy-user&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --recursive&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#82AAFF&quot;&gt; --summarize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2B5581;--shiki-dark:#ECC48D&quot;&gt; s3://bucket-to/copy/to/here/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Total Size&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上記結果がそれぞれ一致していれば、ミスなくコピーできているはずだ。&lt;/p&gt;</content:encoded></item><item><title>DenoKVとSupabaseでTodoリストアプリを作ってみる</title><link>https://blog.kj-dev.net/posts/deno-kv-todo-app-with-auth/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/deno-kv-todo-app-with-auth/</guid><description>Supabaseでの認証を試す</description><pubDate>Sun, 17 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://deno.com/kv&quot;&gt;DenoKV&lt;/a&gt;が発表された。以前からDeno自体は気になっていたので、これを機に触ってみることにした。&lt;/p&gt;
&lt;h2 id=&quot;サンプル-todoリスト&quot;&gt;サンプル: Todoリスト&lt;/h2&gt;
&lt;p&gt;ベースとなるのはこの&lt;a href=&quot;https://github.com/denoland/showcase_todo&quot;&gt;Todoリストアプリ&lt;/a&gt;。
DenoKVを使って複数のユーザーがTodoを追加・削除しながら、Todoリストを共有できる。
サンプルアプリではあるが良くできている。TwitterでDemoが流れてきていたが、リアルタイム並みに高速でリストが同期されるのには驚いた。&lt;/p&gt;
&lt;p&gt;実際にDenoDeployのアカウントを作って試したみた。Github上のリポジトリを指定するだけで、すぐにデプロイが完了する。
上記のサンプルをForkしたものは&lt;a href=&quot;https://early-pike-49.deno.dev/7Lty2NJ5yBK&quot;&gt;こちら&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;実際に見てみると、Demoほど高速で同期はされないようだ。原因はおそらく、Deno KVのWriteリージョン(データがまず書き込まれるリージョン)が現状Virginia, USAで固定になっているため、地域差があるのだろう。現状東京リージョンでは展開されていないので、そこは今後に期待したい。&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/deno-kv-region.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;DenoKVのリージョン&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;denoとsupabaseでweb認証を試す&quot;&gt;DenoとSupabaseでWeb認証を試す&lt;/h2&gt;
&lt;p&gt;上記のアプリでは、誰でもTodoを編集できる。クローズドで認証したユーザーのみがTodoを表示・編集できるようにしてみたくなったので、試してみた。&lt;/p&gt;
&lt;p&gt;Deno初心者かつWeb認証の実装もやったことがなかったので、色々と調べてみたが、分かりやすいYoutube動画があったので、fresh(denoのWebフレームワーク.preactを採用している) + Supabaseで実装してみた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=piHsQdtF8nM&quot;&gt;Build an Auth App with Deno, Fresh And Supabase Part 1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Supabaseでの認証のポイントとしては、freshの&lt;code&gt;routes/_middleware.ts&lt;/code&gt;に以下のコードを追加する。この関数は、あらゆるリクエストをインターセプトする形で実行され、ユーザーの認証を確認することができる。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; handler&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D7DBE0&quot;&gt;  req&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#FFCB8B&quot;&gt; Request&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D7DBE0&quot;&gt;  ctx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#FFCB8B&quot;&gt; MiddleareHandlerContext&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#FFCB8B&quot;&gt;State&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; client&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; createClient&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#D6DEEB;--shiki-dark-font-style:italic&quot;&gt;    Deno&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#FAF39F;--shiki-dark-font-style:italic&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;SUPABASE_URL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#5F7E97&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#D6DEEB;--shiki-dark-font-style:italic&quot;&gt;    Deno&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#FAF39F;--shiki-dark-font-style:italic&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;SUPABASE_KEY&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#D6DEEB&quot;&gt;  ctx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#FAF39F;--shiki-dark-font-style:italic&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#BAEBE2&quot;&gt;supabaseClient&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; client;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; supaCreds&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; getCookies&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#D6DEEB;--shiki-dark-font-style:italic&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#BAEBE2;--shiki-dark-font-style:italic&quot;&gt;headers&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;)[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;supaLogin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;supaCreds) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#D6DEEB&quot;&gt; ctx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C792EA&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C792EA&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#D6DEEB;--shiki-dark-font-style:italic&quot;&gt; client&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#FAF39F;--shiki-dark-font-style:italic&quot;&gt;auth&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;getUser&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#D6DEEB;--shiki-dark-font-style:italic&quot;&gt;supaCreds&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; (error) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#D6DEEB&quot;&gt;    console&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#D6DEEB&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#BAEBE2&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#D6DEEB&quot;&gt;    ctx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#FAF39F;--shiki-dark-font-style:italic&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#BAEBE2&quot;&gt;loggedIn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#FF5874&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  } &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#D6DEEB&quot;&gt;    ctx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#FAF39F;--shiki-dark-font-style:italic&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#BAEBE2&quot;&gt;loggedIn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#FF5874&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#D6DEEB&quot;&gt; ctx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;supabase clinet libraryの&lt;code&gt;client.auth.getUser&lt;/code&gt;を利用することで、ユーザーの認証を確認することができる。&lt;/p&gt;
&lt;p&gt;これが正しい使い方かわからなかったのだが、&lt;a href=&quot;https://supabase.com/docs/reference/javascript/auth-getuser&quot;&gt;公式ドキュメント&lt;/a&gt;にも以下のような記載があった&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;This method is useful for checking if the user is authorized because it validates the user’s access token JWT on the server.
Should be used only when you require the most current user data. For faster results, getSession().session.user is recommended.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;一方で検証できていないが&lt;code&gt;getSession().session.user&lt;/code&gt;を使うこともでき、そちらの方が高速なようだ。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Should be used only when you require the most current user data. For faster results, getSession().session.user is recommended.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;認証されている時のみ表示したいページは、&lt;code&gt;routes/auth/&lt;/code&gt;に配置し、&lt;code&gt;routes/auth/_middleware.ts&lt;/code&gt;に以下のようなコードを追加する。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; handler&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D7DBE0&quot;&gt;  req&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#FFCB8B&quot;&gt; Request&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D7DBE0&quot;&gt;  ctx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#FFCB8B&quot;&gt; MiddleareHandlerContext&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#FFCB8B&quot;&gt;State&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#D6DEEB&quot;&gt;ctx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-light-font-style:inherit;--shiki-dark:#FAF39F;--shiki-dark-font-style:italic&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#BAEBE2&quot;&gt;loggedIn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; Response&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#FF5874&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#5F7E97&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      status&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt; 302&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#5F7E97&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      headers&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;        Location&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#5F7E97&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;      }&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#5F7E97&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#D6DEEB&quot;&gt; ctx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで、認証されていない場合は、&lt;code&gt;/&lt;/code&gt;にリダイレクトされるようになる。&lt;/p&gt;
&lt;p&gt;UIからは、&lt;code&gt;props&lt;/code&gt;を通じて、ctx.stateに設定した値を参照することができる。今回は&lt;code&gt;props.state.loggedIn&lt;/code&gt;を参照することで、 ログイン状態に応じてUIの表示を切り替えることができる。&lt;/p&gt;
&lt;h2 id=&quot;supabaseでユーザーを作成する&quot;&gt;Supabaseでユーザーを作成する&lt;/h2&gt;
&lt;p&gt;通常のWebサービスではWeb上でユーザーを作成することができるものだが、今回はあくまでサンプルかつ知り合いで試しに使うくらいの想定なので、Supabaseの管理画面からユーザーを作成した。&lt;/p&gt;
&lt;p&gt;Supabaseのダッシュボードから簡単に作成でき、Invitationをメールで送るか、すぐにユーザーを作成するかを選択できる。&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/supabase-add-user.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;Supabaseダッシュボードからユーザー追加&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;/h2&gt;
&lt;p&gt;DenoKVと合わせて、Supabaseでの認証も試してみた。やはり実際に手を動かすことで、DenoについてもSupabaseについても理解が深まったのでよかった。&lt;/p&gt;</content:encoded></item><item><title>無料のベースマップサービスまとめ</title><link>https://blog.kj-dev.net/posts/free-basemap-services/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/free-basemap-services/</guid><description>CARTOやMaptilerなど</description><pubDate>Sun, 12 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;無料で使える、ベースマップサービスをまとめた。
Observableでのベースマップのサンプルは&lt;a href=&quot;https://observablehq.com/d/4f63ac3b6875f156&quot;&gt;こちら&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&quot;carto&quot;&gt;CARTO&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://carto.com/basemaps&quot;&gt;CARTO&lt;/a&gt;のベースマップを使用するには、ユーザーアカウントやAPIキーは不要。非商用利用であれば無料で利用できる。&lt;/p&gt;
&lt;h2 id=&quot;maptiler&quot;&gt;Maptiler&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.maptiler.com/&quot;&gt;Maptiler&lt;/a&gt;はクラウドマッピングサービスで、さまざまなマップを提供しており、独自のマップを作成することもできる。&lt;/p&gt;
&lt;p&gt;ベースマップを使用するには、ユーザーアカウントを作成し、APIキーを生成する必要がある。APIリクエストにはFree Tierがあり、月間最大100,000リクエストまで無料で利用でき、Free Tierの使用量を超えても自動的に請求されることはない。&lt;/p&gt;</content:encoded></item><item><title>VivaldiにDeepLプラグインをインストールする</title><link>https://blog.kj-dev.net/posts/vivaldi-deepl-plugin/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/vivaldi-deepl-plugin/</guid><description>VivaldiのTips</description><pubDate>Sun, 18 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://www.deepl.com/translator&quot;&gt;DeepL&lt;/a&gt;は、Google翻訳よりも精度が高いと評判の翻訳サービス。ChromeではDeepLのプラグインがあり、Webページの翻訳が簡単にできるので重宝している。&lt;/p&gt;
&lt;p&gt;最近、Vivaldiを使い始めたのだが、VivaldiでもDeepLプラグインを使うことができたので、その方法を紹介する。&lt;/p&gt;
&lt;h2 id=&quot;pluginのインストール方法&quot;&gt;Pluginのインストール方法&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;VivaldiでChromeウェブストアの&lt;a href=&quot;https://chrome.google.com/webstore/detail/deepl-translate-reading-w/cofdbpoegempjloogbagkncekinflcnj&quot;&gt;DeepLPlugin&lt;/a&gt;のページを開く&lt;/li&gt;
&lt;li&gt;「Chromeに追加」ボタンをクリック&lt;/li&gt;
&lt;li&gt;Popupがあわわれるので「拡張機能を追加」をクリック&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上でインストール完了。&lt;/p&gt;
&lt;p&gt;今まではウェブパネルとしてDeepLのWebサイトを登録して、画面分割しながら、自分でコピペしてDeepLを使っていた。&lt;/p&gt;
&lt;p&gt;やはり、Pluginを使ってWebページに現れるPopupからすぐに翻訳できる方が便利。&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/vivaldi-deepl-plugin.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;Vivaldiでdeepl-pluginを使う&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title>Terraform: dynamicを使ってblock設定の有無を振り分ける</title><link>https://blog.kj-dev.net/posts/terraform-dynamic-block/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/terraform-dynamic-block/</guid><description>はまりがちな`dynamic`の使い方</description><pubDate>Sat, 17 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Terraformでblock自体を設定する・設定しないを振り分けるには、&lt;a href=&quot;https://developer.hashicorp.com/terraform/language/expressions/dynamic-blocks&quot;&gt;&lt;code&gt;dynamic&lt;/code&gt;&lt;/a&gt;を使えばよい。&lt;/p&gt;
&lt;p&gt;しかし、nullishな変数に対して、&lt;code&gt;dynamic&lt;/code&gt;をどう使えばよいかでハマったので、解決法を書いておく。&lt;/p&gt;
&lt;h2 id=&quot;dynamicが必要になるケースは&quot;&gt;&lt;code&gt;dynamic&lt;/code&gt;が必要になるケースは？&lt;/h2&gt;
&lt;p&gt;あるblock自体の有無を振り分けたい時に&lt;code&gt;dynamic&lt;/code&gt;が必要になる。
例えば、GCSの&lt;code&gt;google_storage_bucket_iam_member&lt;/code&gt;リソースの&lt;a href=&quot;https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket_iam#condition&quot;&gt;&lt;code&gt;condition&lt;/code&gt;ブロック&lt;/a&gt;がある。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;// example&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#D6DEEB&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt; &quot;google_storage_bucket_iam_member&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt; &quot;member&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;  bucket   &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;member-bucket&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;  role     &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;hogehoge&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;  member   &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;hugahuga&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;  // conditionはそれ自体がblock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#D6DEEB&quot;&gt;  condition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#D6DEEB&quot;&gt;    content&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      title       &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;my-rule&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      description &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;it is perfect&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      expression  &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;xxx&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここで、以下の&lt;code&gt;locals&lt;/code&gt;を、ループして複数の&lt;code&gt;google_storage_bucket_iam_member&lt;/code&gt;を宣言したいとする。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#D6DEEB&quot;&gt;locals&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;  test-storage &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;    // パターン1: conditionに値あり&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      bucket&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;test1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      role&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;   =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;test1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      member&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;user:test1@example.com&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      condition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# 値があるパターン&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;        title&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;       =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;        description&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;        expression&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;    // パターン2: conditionはnull&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      bucket&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;test2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      role&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;   =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;test2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      member&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;user:test2@example.com&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      condition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; # nullパターン&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;    // パターン3: conditionキー自体なし&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      bucket&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;test3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      role&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;   =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;test3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      member&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;user:test3@example.com&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;# keyがそもそもないパターン&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;パターンとしては3つ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;パターン1: conditionに値あり&lt;/li&gt;
&lt;li&gt;パターン2: conditionはnull&lt;/li&gt;
&lt;li&gt;パターン3: conditionキー自体なし&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;パターン1のみ&lt;code&gt;condition&lt;/code&gt;を設定し、パターン2,3は設定しないようにしたい。&lt;/p&gt;
&lt;p&gt;ここで注意が必要なのだが、&lt;code&gt;condition&lt;/code&gt;はそれ自体ブロックになっている。そのため、下記のように変数を単純にアサインする書き方ができない。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;// 不可: 変数を代入する&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;  condition &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; local&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;someMap&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;また、&lt;code&gt;condition&lt;/code&gt;を設定しない場合は、&lt;code&gt;null&lt;/code&gt;を入れる、といったこともできない。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt;// 不可: 設定しない場合はnull入れる&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;  condition &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt; null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;そこで&lt;code&gt;dynamic&lt;/code&gt;の出番となる。&lt;/p&gt;
&lt;h2 id=&quot;dynamicを使った書き方&quot;&gt;&lt;code&gt;dynamic&lt;/code&gt;を使った書き方&lt;/h2&gt;
&lt;p&gt;以下のように書くことで、パターン1のみ&lt;code&gt;condition&lt;/code&gt;を設定し、パターン2,3は設定しないようにできる。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#D6DEEB&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt; &quot;google_storage_bucket_iam_member&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt; &quot;member&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;  for_each &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt; local&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;test-storage&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;bucket&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;  bucket   &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; each&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;bucket&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;  role     &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; each&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;role&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;  member   &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; each&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;member&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#D6DEEB&quot;&gt;  dynamic&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt; &quot;condition&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;    for_each &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;  try&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#82AAFF&quot;&gt;(each&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#82AAFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#D6DEEB&quot;&gt;    content&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      title       &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  each&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;title&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      description &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  each&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;description&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      expression  &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  each&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;expression&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここがミソ:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;for_each &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;  try&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#82AAFF&quot;&gt;(each&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#82AAFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; []&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;try&lt;/code&gt;は、パターン2,3の場合は空リスト&lt;code&gt;[]&lt;/code&gt;を&lt;code&gt;for_each&lt;/code&gt;に返す。&lt;code&gt;for_each&lt;/code&gt;では処理がなされないので、&lt;code&gt;condition&lt;/code&gt;の設定をスキップできる。&lt;/p&gt;
&lt;h2 id=&quot;dynamic内のfor_eachの注意点&quot;&gt;dynamic内のfor_eachの注意点&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;dynamic&lt;/code&gt;内での&lt;code&gt;each&lt;/code&gt;の挙動には注意が必要。&lt;/p&gt;
&lt;p&gt;一見、&lt;code&gt;each.value&lt;/code&gt;には&lt;code&gt;dynamic&lt;/code&gt;内の&lt;code&gt;for_each&lt;/code&gt;で指定した値が入ってくるのではと思われる。&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#D6DEEB&quot;&gt;  dynamic&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt; &quot;condition&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;    for_each &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;  try&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#82AAFF&quot;&gt;(each&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#82AAFF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#F78C6C&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#D6DEEB&quot;&gt;    content&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      title       &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  each&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--shiki-light:#C2C3C5;--shiki-light-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic&quot;&gt; // each.valueは`[1]`が入ってこないの？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      description &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  each&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;description&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;      expression  &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;  each&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#7FDBCA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#C5E478&quot;&gt;expression&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#7FDBCA&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;と思って混乱したのだが、ちゃんと&lt;a href=&quot;https://developer.hashicorp.com/terraform/language/expressions/dynamic-blocks&quot;&gt;公式&lt;/a&gt;に書いてあった。
dynamicのfor_eachは通常と少し違う動きをする。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The iterator argument (optional) sets the name of a temporary variable that represents the current element of the complex value. If omitted, the name of the variable defaults to the label of the dynamic block (“setting” in the example above).&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;つまり、&lt;code&gt;dynamic&lt;/code&gt;内の&lt;code&gt;for_each&lt;/code&gt;で指定した変数にアクセスするには、&lt;code&gt;each&lt;/code&gt;は使わない。&lt;/p&gt;
&lt;p&gt;今回のケースだと、&lt;code&gt;condition.key&lt;/code&gt;/&lt;code&gt;condition.value&lt;/code&gt;を使えば、dynamicのfor_eachの変数にアクセスできる。
よくよく見ると、公式の例でも、&lt;code&gt;dynami&lt;/code&gt;cの&lt;code&gt;for_each&lt;/code&gt;は&lt;code&gt;each.key&lt;/code&gt;/&lt;code&gt;each.value&lt;/code&gt;は使ってない。&lt;/p&gt;</content:encoded></item><item><title>CloudAssetInventoryでGCP内のリソースを確認する</title><link>https://blog.kj-dev.net/posts/check-when-deleting-gcp-project/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/check-when-deleting-gcp-project/</guid><description>コンソールからまるっとリソースを閲覧</description><pubDate>Fri, 09 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;あるGCP Projectを削除することになった。削除する前にそのProjectにどんなリソースが存在しているか？想定外の消してはまずいリソースがないか？を確認したくなった。&lt;/p&gt;
&lt;p&gt;ググっても意外とすぐに方法は出てこないのだが、&lt;a href=&quot;https://cloud.google.com/asset-inventory/docs/overview?hl=ja&quot;&gt;Cloud Asset Inventory&lt;/a&gt;を使うと簡単に確認できる。&lt;/p&gt;
&lt;p&gt;GCPコンソールの検索バーで「asset inventory」と打てば出てくる。WebUI上で簡単にProject内に存在するアセットを確認できる。&lt;/p&gt;
&lt;p&gt;サービス別はもちろん、リージョン別でもアセットを表示してくれる。&lt;/p&gt;
&lt;p&gt;支払料金をSKUごとに表示するといったことも可能。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GCPコンソール上で「お支払い」-&gt; 「レポート」と遷移すると月次の利用料金がグラフで表示される。&lt;/li&gt;
&lt;li&gt;右側のフィルタで「グループ条件」-&gt; 「SKU」を選ぶと、SKU単位でのサービス利用料金が見れる。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これで直近想定してないサービスの利用や課金がされていないか確認できる。&lt;/p&gt;</content:encoded></item><item><title>Airflowを学ぶにはAirflow Summitの動画を見るのが良い</title><link>https://blog.kj-dev.net/posts/airflow-summit-2022/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/airflow-summit-2022/</guid><description>Airflow Summit 2022の紹介</description><pubDate>Wed, 01 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Airflow Summit 2022 の各セッションが Youtube に動画が上がってる。Airflow の専門家たちが様々なお題をテーマに Talk している。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://airflowsummit.org/sessions/2022/&quot;&gt;Airflow Summit 2022 sessions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Airflow の最新の動向やベストプラクティスをキャッチアップしたい。でも公式ドキュメントだけではつらい。そんな Airflow 中級者を目指す人（というか自分）にもわかりやすく、とても良いリソース。&lt;/p&gt;
&lt;p&gt;興味のあるテーマについて視聴してみることをおすすめする。自分が視聴して良かったセッションについていくつか紹介する。&lt;/p&gt;
&lt;h2 id=&quot;dynamic-dags-the-new-horizon&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=P6sqdPr7h1M&quot;&gt;Dynamic Dags: The New Horizon&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;今まで For ループ内で作ってた並列タスクを、&lt;code&gt;.expand&lt;/code&gt;メソッドでクリーンにかけるようになったよ、というお話。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AirflowUI での並列タスクの表示もより見やすくなった&lt;/li&gt;
&lt;li&gt;Airflow2.3 以降で利用可能&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.expand&lt;/code&gt;できるのは TopLevel のみ。Task の Runtime では使えない。
&lt;ul&gt;
&lt;li&gt;v2.4 以降に TopLevel 以外でも呼べるようにしたいとのこと。 -&gt; Doc 見る限り現時点での最新バージョン 2.5.2 でも実装されてなさそう&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;all-about-deferrables&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PYTu3PWVR60&quot;&gt;All About Deferrables&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Deferrable Operator ってなに？から基本を教えてくれる初心者向けの Talk.わかりやすい。&lt;/p&gt;
&lt;p&gt;個人的にわかりやすかった、Why defferable operator?が一発でわかるスライド：&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;@/assets/images/posts/deferrable.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;why-deferrable&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;Deferrable が何なのか、いつ使うのか、公式ドキュメントだけでは理解が難しいと感じている人にとっては特におすすめ。&lt;/p&gt;
&lt;h2 id=&quot;happy-dags-happy-teammates-how-a-little-cicd-can-go-a-long-way&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Wf5VNH9su9I&quot;&gt;Happy DAGs Happy Teammates How a little CICD can go a long way&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CICD にまつわるショートトーク。&lt;/p&gt;
&lt;p&gt;あまり具体的な話は出ないが、CICD 周りを考えるうえでのヒントが幾つかある感じ。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Airflow Breeze なるものの存在を知った。Local で動かす Airflow で DAG を検証するのに良いらしい
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/apache/airflow/blob/main/BREEZE.rst#airflow-breeze-ci-environment&quot;&gt;公式ドキュメント&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://future-architect.github.io/articles/20210528a/&quot;&gt;解説記事&lt;/a&gt;も落ちていたので張っておく&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DAG の Test についての Resource
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://airflowsummit.org/slides/2022/d1-HappyDags-Leah.pdf&quot;&gt;ここ&lt;/a&gt;のスライド PDF の P13 あたりにリンク集がある。いずれ読みたい。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>taskデコレータを使ってtask_idを変更する(Airflow v2.2以前)</title><link>https://blog.kj-dev.net/posts/airflow-decorator/</link><guid isPermaLink="true">https://blog.kj-dev.net/posts/airflow-decorator/</guid><description>ForLoopで複数生成したタスクのtask_idを変更する</description><pubDate>Fri, 23 Sep 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://forum.astronomer.io/t/change-task-id-when-calling-function-using-taskflow-api/1540&quot;&gt;ここ&lt;/a&gt;に書いてある通りなのだが、なかなか見つからなかったので。&lt;/p&gt;
&lt;p&gt;Airflow v2.2以前で、&lt;code&gt;@task&lt;/code&gt;デコレータで生成したタスクを ForLoop で複数生成したい場合:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; airflow&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;decorators &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; task&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#82AAFF&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;task&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; say_hi&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Hi&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;names &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Bob&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Charlie&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Jane&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; name &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; names&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    start &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; say_hi&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これでコードとしては動くが、loop で生成される&lt;code&gt;task_id&lt;/code&gt; は&lt;code&gt;say_hi_1&lt;/code&gt;, &lt;code&gt;say_hi_2&lt;/code&gt;, …と単に連番が振られるだけになってしまう。&lt;/p&gt;
&lt;p&gt;そこで以下のようにすれば、好みの&lt;code&gt;task_id&lt;/code&gt; を設定できる:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#82AAFF&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; name &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; names&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    start &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; task&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;say_hi&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D7DBE0&quot;&gt;task_id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;&quot;say_hi_to_&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;何のことはない、&lt;code&gt;@task&lt;/code&gt;は decorator なので、関数を引数とした関数として使えるということ。
少々読みずらくはなってしまうが、Airflow v2.2 以前で&lt;code&gt;@task&lt;/code&gt;を使うには、いろいろと不便が伴うので仕方ない。&lt;/p&gt;
&lt;h2 id=&quot;airflow-v23-以降について&quot;&gt;Airflow v2.3 以降について&lt;/h2&gt;
&lt;p&gt;Airflow v2.3以降では、以下のように&lt;code&gt;override&lt;/code&gt;メソッドで&lt;code&gt;task_id&lt;/code&gt;を設定できるようだ:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;task&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; say_hi&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Hi&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;names &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Bob&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Charlie&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Jane&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; name &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-light-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt; names&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    say_hi&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D7DBE0&quot;&gt;task_id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;&quot;say_hi_to_&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1976D2;--shiki-dark:#82AAFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;    start &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt; say_hi&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;また、少し話はそれるが、v2.3 以降なら ForLoop の代わりに&lt;code&gt;expand&lt;/code&gt;メソッドが使える:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes min-light night-owl&quot; style=&quot;--shiki-light:#24292eff;--shiki-dark:#d6deeb;--shiki-light-bg:#ffffff;--shiki-dark-bg:#011627; overflow-x: auto;--file-name-offset: -0.75rem;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic&quot;&gt;task&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic&quot;&gt; say_hi&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#FF9800;--shiki-dark:#7FDBCA&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#C5E478&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Hi&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D9F5DD&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;names &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Bob&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Charlie&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#ECC48D&quot;&gt;Jane&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#D9F5DD&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D9F5DD&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292EFF;--shiki-dark:#D6DEEB&quot;&gt;say_hi&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B2CCD6&quot;&gt;expand&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D7DBE0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D32F2F;--shiki-dark:#C792EA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#82AAFF&quot;&gt;names&lt;/span&gt;&lt;span style=&quot;--shiki-light:#212121;--shiki-dark:#D6DEEB&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;が、どうやら&lt;code&gt;task_id&lt;/code&gt;は最初の例のように、&lt;code&gt;say_hi_1&lt;/code&gt;, &lt;code&gt;say_hi_2&lt;/code&gt;, …と連番で振られてしまい、任意の値は設定できないようだ。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.astronomer.io/learn/dynamic-tasks#:~:text=Some%20parameters%20can%27t%20be%20mapped.%20For%20example%2C%20task_id%2C%20pool%2C%20and%20many%20BaseOperator%20arguments.&quot;&gt;Astronomer のページ&lt;/a&gt; でも&lt;code&gt;task_id&lt;/code&gt;はマップ不可と言及されている:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Some parameters can’t be mapped. For example, task_id, pool, and many BaseOperator arguments.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;既存の DAG で&lt;code&gt;expand&lt;/code&gt;を取り入れる場合、&lt;code&gt;task_id&lt;/code&gt;が変わってしまえば、過去タスクのログが見えずらくなってしまう。
&lt;code&gt;expand&lt;/code&gt;メソッドは便利だが、&lt;code&gt;task_id&lt;/code&gt;が任意の値で設定できない点は注意が必要そうだ。&lt;/p&gt;</content:encoded></item></channel></rss>